Repository: warrensbox/terraform-switcher (go)

Issue:
tfswitch ignores binary flag
Hi everyone, 

I've been using tfswitch to handle the Terraform installation, but some times the binary flag is ignored installing the binary in the user's home directory. 

This is how Terraform is being installed:
```
tfswitch --default "$TF_DEFAULT_VERSION" --bin "$GH_BIN_DIR/terraform"
```

For example:

This isn't part of the `GITHUB_PATH`.

```
22:49:52.967 INFO Checksum file signature verification successful  
22:49:52.997 INFO Deleting "/home/runner/.terraform.versions/terraform_1.10.5_SHA256SUMS"  
22:49:52.999 INFO Deleting "/home/runner/.terraform.versions/terraform_1.10.5_SHA256SUMS.72D7468F.sig"  
22:49:54.670 WARN Run `export PATH="$PATH:/home/runner/bin"` to append "/home/runner/bin/terraform" to $PATH  
22:49:54.670 INFO Switched Terraform to version "1.10.5"  
```

This random dir is part of the `GITHUB_PATH`.

But in other occasions, it does respect the folder location given the following output:
```
22:54:52.228 INFO Checksum file signature verification successful  
22:54:52.252 INFO Deleting "/home/runner/.terraform.versions/terraform_1.10.5_SHA256SUMS"  
22:54:52.253 INFO Deleting "/home/runner/.terraform.versions/terraform_1.10.5_SHA256SUMS.72D7468F.sig"  
22:54:53.500 WARN Run `export PATH="$PATH:/tmp/tmp.xzYePlXnBMgh_data_bin"` to append "/tmp/tmp.xzYePlXnBMgh_data_bin/terraform" to $PATH  
22:54:53.500 INFO Switched Terraform to version "1.10.5"  
```

This is causing random failures while running our CI checks. 

tfswitch version: v1.4.0

Thanks.
false path warning on Windows in version 1.4.1
I think there's a problem with #549  when run on Windows. I'm getting a waning about exporting path=...... to append to my path but it's already there. DIdn't have this issue on tfswitch 1.3.0

I believe the issue with 549 is you're splitting on : but on Windows the path separator is ; so the check isn't working.

Also, the suggestion to run export isn't valid on Windows so either don't show it or show a different message with the proper command.


Discussion:
It's probably not obvious: if the custom `bin` path does not exist, `tfswitch` falls back to installing into `~/bin` directory, which may be the use case that you're facing.

Please try and add `mkdir -p "$GH_BIN_DIR"` command right before the `tfswitch` command in your CI and see if it helps.

Ref: https://github.com/warrensbox/terraform-switcher/issues/543

~I'll also work on adding some more logging around this feature to make it more obvious and clear.~ Nevermind me, if you run `tfswitch` with `--log-level DEBUG` you'll see it spitting out a log message about non-existent `--bin` dir (and then it falls back to installing into "bin" dir inside home dir).
Thanks for reporting.
Please let me know if `mkdir` solution resolves the issue for you. Else I'll re-open this issue to figure it out.
I'm using ephemeral GitHub actions runner, by using the ARC, the directory is being created using the `mktemp` command and then adding the path to the GitHub path environment variable.

Example: `GH_BIN_DIR=$(mktemp --directory --suffix=gh_data_bin)`, and then I'm adding the output as `echo "GH_BIN_DIR=$GH_BIN_DIR" >> "$GITHUB_OUTPUT"`.

When the step runs, I know the directory was created because the environment variable is present when I'm installing Terraform via tfswitch:

```
run: |
    echo "::notice::Installing Terraform using tfswitch"
    tfswitch --default "$TF_DEFAULT_VERSION" --bin "$GH_BIN_DIR/terraform"
env: 
    GH_BIN_DIR: ${{ steps.mktemp_dir.outputs.GH_BIN_DIR }}
```

When the workflow runs I see `GH_BIN_DIR: /tmp/tmp.FcCuvny2kPgh_data_bin` (this output was taken from the workflow that failed). 
Would you mind replacing the `run` block with the below and providing full output starting from `Installing Terraform using tfswitch` line?
```yaml
run: |
    echo "::notice::Installing Terraform using tfswitch"
    ls -ld "$GH_BIN_DIR"
    tfswitch --default "$TF_DEFAULT_VERSION" --bin "$GH_BIN_DIR/terraform" --log-level DEBUG
env: 
    GH_BIN_DIR: ${{ steps.mktemp_dir.outputs.GH_BIN_DIR }}
```
(added `ls -ld "$GH_BIN_DIR"` command and `--log-level DEBUG` flag for `tfswitch`)
Thanks.
I’ll add them and let you know if it fails, because as I mentioned this doesn’t seem to follow a pattern, thank you. 

Note: I don't think it's a problem with  the directory creation, because it should have exit the step given the `set -e` option defined in the workflow I have.
@javierlga I guess I've found the root cause of the issue. Stay tuned.
I didn't expect this to surface this quick =)
We just have no Windows-based workstations at hand to check what's correct under that OS.

We'd be happy to add Windows-specific code bits and messaging.
Could you please provide:
* An example `PATH` env var value: the one you use «_to append to my path but it's already there_» would be ideal as it has all relevant data in it 👍🏻 
* And example command to append dir to `PATH` under Windows.

Thanks in advance 🤝 
Example path that include both SYSTEM and USER paths (obtained by running `path` in a command prompt)

PATH=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;C:\Program Files\dotnet\;C:\Users\mj790\AppData\Local\Microsoft\WindowsApps;C:\Users\mj790\AppData\Local\Programs\Microsoft VS Code\bin;C:\users\mj790\bin;

What I see when I run tfswitch:

WARN Run `export PATH="$PATH:C:\Users\mj790\bin"` to append "C:\\Users\\mj790\\bin\\terraform.exe" to $PATH


As for giving people a command to run on Windows, I wouldn't. Depending on whether you're using the command prompt or a powershell window, whether you have admin rights or not (and whether you want to adjust USER or SYSTEM paths) and the fact that you can have placeholders such as %USERPROFILE% in your path that can get expanded if you run the wrong thing, it's not a one liner like the warning above (it's probably like 3-5 lines of powershell commands to do it cleanly). Just my opinion... maybe I'm wrong 😃 
Oh, so you mean we'd better suppress that message on Windows at all to avoid any sort of confusion? 🤔

Patch:
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,4 @@
+[install.sh]
+indent_style = space
+indent_size = 2
+switch_case_indent = true
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,10 +1,9 @@
 ---
 name: Feature request
 about: Suggest an idea for this project
-title: ''
+title: ""
 labels: enhancement
 assignees: warrensbox
-
 ---
 
 **Is your feature request related to a problem? Please describe.**
@@ -19,61 +18,80 @@ A clear and concise description of any alternative solutions or features you've
 **Additional context**
 Add any other context or screenshots about the feature request here.
 
-### If you would like to contribute to the code, see step-by-step instructions here:
+### If you would like to contribute to the code, see step-by-step instructions here
 
 ## Required version
+
 ```sh
 go version 1.13
 ```
 
 ### Step 1 - Create workspace
-*Skip this step if you already have a github go workspace*   
-Create a github workspace.
-<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-workspace.gif" alt="drawing" style="width: 600px;"/>   
+
+_Skip this step if you already have a GitHub Go workspace_  
+Create a GitHub workspace.
+<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-workspace.gif" alt="drawing" style="width: 600px;"/>
 
 ### Step 2 - Set GOPATH
-*Skip this step if you already have a github go workspace*    
-Export your GOPATH environment variable in your `go` directory.   
+
+_Skip this step if you already have a GitHub Go workspace_  
+Export your GOPATH environment variable in your `go` directory.
+
 ```sh
 export GOPATH=`pwd`
 ```
-<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-gopath.gif" alt="drawing" style="width: 600px;"/>   
+
+<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-gopath.gif" alt="drawing" style="width: 600px;"/>
 
 ### Step 3 - Clone repository
-Git clone this repository.  
-```sh 
+
+Git clone this repository.
+
+```sh
 git clone git@github.com:warrensbox/terraform-switcher.git
 ```
-<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-git-clone.gif" alt="drawing" style="width: 600px;"/>  
+
+<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-git-clone.gif" alt="drawing" style="width: 600px;"/>
 
 ### Step 4 - Get dependencies
-Go get all the dependencies.   
 
-```sh 
+Go get all the dependencies.
+
+```sh
 go mod download
 ```
-```sh 
+
+```sh
 go get -v -t -d ./...
 ```
+
 Test the code (optional).
-```sh  
+
+```sh
 go vet -tests=false ./...
 ```
-```sh 
+
+```sh
 go test -v ./...
 ```
-<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-go-get.gif" alt="drawing" style="width: 600px;"/>  
+
+<img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-go-get.gif" alt="drawing" style="width: 600px;"/>
 
 ### Step 5 - Build executable
-Create a new branch.   
-```sh 
+
+Create a new branch.
+
+```sh
 git checkout -b feature/put-your-branch-name-here
 ```
+
 Refactor and add new features to the code.  
-Go build the code.   
-```sh 
+Go build the code.
+
+```sh
 go build -o test-tfswitch
 ```
+
 Test the code and create a new pull request!
 
 <img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-build.gif" alt="drawing" style="width: 600px;"/>
diff --git a/.github/labeler.yml b/.github/labeler.yml
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -5,38 +5,38 @@
 version: v1
 
 labels:
-  - label: 'chore'
+  - label: "chore"
     matcher:
-      title: '^(c(hore|i)|style):'
-      branch: '^(c(hore|i)|style)/'
-      commits: '^(c(hore|i)|style):'
+      title: "^(c(hore|i)|style):"
+      branch: "^(c(hore|i)|style)/"
+      commits: "^(c(hore|i)|style):"
 
-  - label: 'dependencies'
+  - label: "dependencies"
     matcher:
-      title: '^deps:'
-      branch: '^deps/'
-      commits: '^deps:'
+      title: "^deps:"
+      branch: "^deps/"
+      commits: "^deps:"
 
-  - label: 'documentation'
+  - label: "documentation"
     matcher:
-      title: '^docs?:'
-      branch: '^docs?/'
-      commits: '^docs?:'
+      title: "^docs?:"
+      branch: "^docs?/"
+      commits: "^docs?:"
 
-  - label: 'enhancement'
+  - label: "enhancement"
     matcher:
-      title: '^fix:'
-      branch: '^fix/'
-      commits: '^fix:'
+      title: "^fix:"
+      branch: "^fix/"
+      commits: "^fix:"
 
-  - label: 'golang'
+  - label: "golang"
     matcher:
-      title: '^go(lang)?:'
-      branch: '^go(lang)?/'
-      commits: '^go(lang)?:'
+      title: "^go(lang)?:"
+      branch: "^go(lang)?/"
+      commits: "^go(lang)?:"
 
-  - label: 'new feature'
+  - label: "new feature"
     matcher:
-      title: '^feat(ure)?:'
-      branch: '^feat(ure)?/'
-      commits: '^feat(ure)?:'
+      title: "^feat(ure)?:"
+      branch: "^feat(ure)?/"
+      commits: "^feat(ure)?:"
diff --git a/.github/linters/.cspell.json b/.github/linters/.cspell.json
new file mode 100644
--- /dev/null
+++ b/.github/linters/.cspell.json
@@ -0,0 +1,6 @@
+{
+  "version": "0.2",
+  "language": "en",
+  "ignorePaths": [],
+  "words": []
+}
diff --git a/.github/linters/.golangci.yml b/.github/linters/.golangci.yml
new file mode 100644
--- /dev/null
+++ b/.github/linters/.golangci.yml
@@ -0,0 +1,2 @@
+run:
+  timeout: 5m
diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml
new file mode 100644
--- /dev/null
+++ b/.github/linters/.markdown-lint.yml
@@ -0,0 +1,18 @@
+---
+###############
+# Rules by id #
+###############
+MD004: false # Unordered list style
+MD007:
+  indent: 2 # Unordered list indentation
+MD013: false # Disable line length checks (to allow flexibility)
+MD026:
+  punctuation: ".,;:!。，；:" # List of not allowed
+MD029: false # Ordered list item prefix
+MD033: false # Allow inline HTML
+MD036: false # Emphasis used instead of a heading
+
+#################
+# Rules by tags #
+#################
+blank_lines: false # Error on blank lines
diff --git a/.github/linters/.yaml-lint.yml b/.github/linters/.yaml-lint.yml
new file mode 100644
--- /dev/null
+++ b/.github/linters/.yaml-lint.yml
@@ -0,0 +1,53 @@
+---
+# This config is used by `super-linter`
+# https://github.com/super-linter/super-linter/blob/main/README.md?plain=1#L409
+# https://github.com/super-linter/super-linter/blob/main/TEMPLATES/.yaml-lint.yml
+rules:
+  braces:
+    level: warning
+    min-spaces-inside: 0
+    max-spaces-inside: 0
+    min-spaces-inside-empty: 1
+    max-spaces-inside-empty: 5
+  brackets:
+    level: warning
+    min-spaces-inside: 0
+    max-spaces-inside: 0
+    min-spaces-inside-empty: 1
+    max-spaces-inside-empty: 5
+  colons:
+    level: warning
+    max-spaces-before: 0
+    max-spaces-after: 1
+  commas:
+    level: warning
+    max-spaces-before: 0
+    min-spaces-after: 1
+    max-spaces-after: 1
+  comments: disable
+  comments-indentation: disable
+  document-end: disable
+  document-start: disable
+  empty-lines:
+    level: warning
+    max: 2
+    max-start: 0
+    max-end: 0
+  hyphens:
+    level: warning
+    max-spaces-after: 1
+  indentation:
+    level: warning
+    spaces: consistent
+    indent-sequences: true
+    check-multi-line-strings: false
+  key-duplicates: enable
+  line-length:
+    level: warning
+    max: 185
+    allow-non-breakable-words: true
+    allow-non-breakable-inline-mappings: true
+  new-line-at-end-of-file: enable
+  new-lines:
+    type: unix
+  trailing-spaces: disable
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -4,10 +4,10 @@ permissions: {} # yamllint disable-line rule:braces
 on:
   push:
     branches:
-      - '*'       # matches every branch that doesn't contain a '/'
-      - '*/*'     # matches every branch containing a single '/'
-      - '**'      # matches every branch
-      - '!master' # excludes `master` branch
+      - "*" # matches every branch that doesn't contain a '/'
+      - "*/*" # matches every branch containing a single '/'
+      - "**" # matches every branch
+      - "!master" # excludes `master` branch
 
 env:
   CGO_ENABLED: 0 # Build statically linked binaries
@@ -22,7 +22,7 @@ jobs:
       - name: Install Go
         uses: actions/setup-go@v5
         with:
-          go-version-file: 'go.mod'
+          go-version-file: "go.mod"
           cache: false
 
       - name: Check vet
@@ -46,38 +46,37 @@ jobs:
         os: [ubuntu-latest]
     runs-on: ${{ matrix.os }}
     steps:
+      - name: Checkout repo
+        uses: actions/checkout@v4
 
-    - name: Checkout repo
-      uses: actions/checkout@v4
-
-    - name: Install Go
-      uses: actions/setup-go@v5
-      with:
-        go-version-file: 'go.mod'
-        cache: false
+      - name: Install Go
+        uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+          cache: false
 
-    - name: Build code
-      run: go build -v ./...
+      - name: Build code
+        run: go build -v ./...
 
-    - name: Running unit tests
-      run: |
-        go test -v ./...
+      - name: Running unit tests
+        run: |
+          go test -v ./...
 
-    - name: Running integration tests
-      run: |
-        set -e
-        mkdir -p build
-        go build -v -o build/tfswitch
-        mkdir `pwd`/bin/
-        find ./test-data/integration-tests/* -type d -print0 | while read -r -d $'\0' TEST_PATH; do
-            if test -f "${TEST_PATH}/.tfswitch.toml"
-            then
-                cp "${TEST_PATH}/.tfswitch.toml" ~/
-            else
-                rm -f ~/.tfswitch.toml
-            fi
-            ./build/tfswitch -c "${TEST_PATH}" -b `pwd`/bin/terraform || exit 1
-        done
+      - name: Running integration tests
+        run: |
+          set -e
+          mkdir -p build
+          go build -v -o build/tfswitch
+          mkdir "$(pwd)/bin/"
+          find ./test-data/integration-tests/* -type d -print0 | while read -r -d $'\0' TEST_PATH; do
+              if test -f "${TEST_PATH}/.tfswitch.toml"
+              then
+                  cp "${TEST_PATH}/.tfswitch.toml" ~/
+              else
+                  rm -f ~/.tfswitch.toml
+              fi
+              ./build/tfswitch -c "${TEST_PATH}" -b "$(pwd)/bin/terraform" || exit 1
+          done
 
   integration_tests_windows:
     strategy:
@@ -85,16 +84,15 @@ jobs:
         os: [windows-latest]
     runs-on: ${{ matrix.os }}
     steps:
+      - name: Checkout repo
+        uses: actions/checkout@v4
 
-    - name: Checkout repo
-      uses: actions/checkout@v4
-
-    - name: Install Go
-      uses: actions/setup-go@v5
-      with:
-        go-version-file: 'go.mod'
-        cache: false
+      - name: Install Go
+        uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+          cache: false
 
-    - name: Running unit tests
-      run: |
-        go test -v ./...
+      - name: Running unit tests
+        run: |
+          go test -v ./...
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -14,9 +14,9 @@ permissions: {} # yamllint disable-line rule:braces
 
 on:
   push:
-    branches: [ "master" ]
+    branches: ["master"]
   pull_request:
-    branches: [ "master" ]
+    branches: ["master"]
     paths-ignore:
       - "**/.*"
       - "**/*.md"
@@ -24,7 +24,7 @@ on:
       - "test-data/**/*"
       - "www/**/*"
   schedule:
-    - cron: '16 12 * * 1'
+    - cron: "16 12 * * 1"
 
 jobs:
   analyze:
@@ -65,7 +65,7 @@ jobs:
       - name: Set up Go
         uses: actions/setup-go@v5
         with:
-          go-version-file: 'go.mod'
+          go-version-file: "go.mod"
           cache: false
 
       # Initializes the CodeQL tools for scanning.
@@ -78,7 +78,8 @@ jobs:
           # By default, queries listed here will override any specified in a config file.
           # Prefix the list here with "+" to use these queries and those in the config file.
 
-          # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
+          # For more details on CodeQL's query packs, refer to:
+          # https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
           # queries: security-extended,security-and-quality
 
       # If the analyze step fails for one of the languages you are analyzing with
diff --git a/.github/workflows/goreport.yml b/.github/workflows/goreport.yml
--- a/.github/workflows/goreport.yml
+++ b/.github/workflows/goreport.yml
@@ -1,9 +1,10 @@
 name: Update goreport card
+permissions: {} # yamllint disable-line rule:braces
 
 on:
   push:
     branches:
-      - 'master'
+      - "master"
 
 jobs:
   goreport:
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,10 +1,11 @@
+name: Update Go Module Index
+permissions: {} # yamllint disable-line rule:braces
+
 on:
   release:
     types:
       - published
 
-name: Update Go Module Index
-
 jobs:
   bump-index:
     runs-on: ubuntu-latest
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -4,6 +4,7 @@ permissions: {} # yamllint disable-line rule:braces
 on:
   workflow_dispatch:
     inputs:
+      #checkov:skip=CKV_GHA_7: This is a manual step intended for user input
       name:
         description: "Enter - major, minor, patch"
         default: "patch"
@@ -15,130 +16,130 @@ jobs:
       contents: write
 
     steps:
-    - name: Check if provided input is valid
-      run: |
-        echo "Semantic Version: ${{ github.event.inputs.name }}"
-        VERSION=${{ github.event.inputs.name }}
-        if [ "$VERSION" != "major" ] && [ "$VERSION" != "minor" ] && [ "$VERSION" != "patch" ]; then
-            echo "Error: Provided input string must be 'major', 'minor', or 'patch'"
-            exit 1
-        fi
-
-    # Checkout code from repo
-    - name: Checkout repo
-      uses: actions/checkout@v4
-      with:
-        ref: ${{ github.head_ref }} # required for better experience using pre-releases
-        fetch-depth: '0'
-
-    # Install Go
-    - name: Install Go
-      uses: actions/setup-go@v5
-      with:
-        go-version-file: 'go.mod'
-        cache: false
-
-    # Double check Go version
-    - name: Go version
-      id: Version
-      run: go version
-
-    # Download Go dependencies
-    - name: Go download
-      run: go mod download
-
-    # Test to see if tfswitch works with --help
-    - name: Go build
-      env:
-        CGO_ENABLED: 0 # Build statically linked binaries
-      run: mkdir -p build && go build -v -o build/tfswitch && build/tfswitch --help
-      continue-on-error: false
-
-    - name: Create dry tag
-      uses: anothrNick/github-tag-action@1.71.0
-      id: semver-tag-dry
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        WITH_V: true
-        INITIAL_VERSION: 1.0.0
-        RELEASE_BRANCHES: master
-        DEFAULT_BUMP: ${{ github.event.inputs.name }}
-        PRERELEASE: false
-        DRY_RUN: true # Only get the tag - dry
-        VERBOSE: false
-
-    # Echo version
-    - name: Echo version
-      run: |
-        echo ${{ steps.semver-tag-dry.outputs.tag }}
-
-    # Push the changes to remote
-    # - name: Push changes
-    #   uses: ad-m/github-push-action@master
-    #   with:
-    #     github_token: ${{ secrets.GITHUB_TOKEN }}
-    #     branch: release-${{ steps.semver-tag-dry.outputs.tag }}
-
-    # - name: Create Pull Request
-    #   id: cpr
-    #   uses: peter-evans/create-pull-request@v6
-    #   with:
-    #     token: ${{ secrets.GITHUB_TOKEN }}
-    #     branch: release-${{ steps.semver-tag-dry.outputs.tag }}
-    #     title: Release ${{ steps.semver-tag-dry.outputs.tag }}
-    #     labels: automerge
-
-    # - name: Check outputs
-    #   if: ${{ steps.cpr.outputs.pull-request-number }}
-    #   run: |
-    #     echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
-    #     echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
-
-    # - name: Merging release PR
-    #   run: gh pr merge --merge --auto "${{ steps.cpr.outputs.pull-request-number }}"
-    #   env:
-    #     GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
-
-    # Introduce new tag (for real)
-    - name: Bump version and push tag
-      uses: anothrNick/github-tag-action@1.71.0
-      id: semver-tag
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        WITH_V: true
-        INITIAL_VERSION: 1.0.0
-        RELEASE_BRANCHES: master
-        DEFAULT_BUMP: ${{ github.event.inputs.name }}
-        PRERELEASE: false
-        DRY_RUN: false # Not dry
-        VERBOSE: true
-
-    # Run goreleaser to create new binaries
-    - name: Run GoReleaser
-      uses: goreleaser/goreleaser-action@v6
-      with:
-        version: latest
-        args: release --clean
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-        RELEASE_VERSION: ${{ steps.semver-tag.outputs.tag }}
-        PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
-        NO_CREATE_CHANGELOG: false
-
-    # Install Python
-    - name: Install Python
-      uses: actions/setup-python@v5
-      with:
-        python-version: 3.x
-
-    # Install Py dependencies
-    - name: Install dependencies
-      run: |
-        python -m pip install --upgrade pip
-        pip install mkdocs-material
-
-   # Build WWW page
-    - name: Build page
-      run: cd www && mkdocs gh-deploy --force
-      env:
-        GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      - name: Check if provided input is valid
+        run: |
+          echo "Semantic Version: ${{ github.event.inputs.name }}"
+          VERSION=${{ github.event.inputs.name }}
+          if [ "$VERSION" != "major" ] && [ "$VERSION" != "minor" ] && [ "$VERSION" != "patch" ]; then
+              echo "Error: Provided input string must be 'major', 'minor', or 'patch'"
+              exit 1
+          fi
+
+      # Checkout code from repo
+      - name: Checkout repo
+        uses: actions/checkout@v4
+        with:
+          ref: ${{ github.head_ref }} # required for better experience using pre-releases
+          fetch-depth: "0"
+
+      # Install Go
+      - name: Install Go
+        uses: actions/setup-go@v5
+        with:
+          go-version-file: "go.mod"
+          cache: false
+
+      # Double check Go version
+      - name: Go version
+        id: Version
+        run: go version
+
+      # Download Go dependencies
+      - name: Go download
+        run: go mod download
+
+      # Test to see if tfswitch works with --help
+      - name: Go build
+        env:
+          CGO_ENABLED: 0 # Build statically linked binaries
+        run: mkdir -p build && go build -v -o build/tfswitch && build/tfswitch --help
+        continue-on-error: false
+
+      - name: Create dry tag
+        uses: anothrNick/github-tag-action@1.71.0
+        id: semver-tag-dry
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          WITH_V: true
+          INITIAL_VERSION: 1.0.0
+          RELEASE_BRANCHES: master
+          DEFAULT_BUMP: ${{ github.event.inputs.name }}
+          PRERELEASE: false
+          DRY_RUN: true # Only get the tag - dry
+          VERBOSE: false
+
+      # Echo version
+      - name: Echo version
+        run: |
+          echo ${{ steps.semver-tag-dry.outputs.tag }}
+
+      # Push the changes to remote
+      # - name: Push changes
+      #   uses: ad-m/github-push-action@master
+      #   with:
+      #     github_token: ${{ secrets.GITHUB_TOKEN }}
+      #     branch: release-${{ steps.semver-tag-dry.outputs.tag }}
+
+      # - name: Create Pull Request
+      #   id: cpr
+      #   uses: peter-evans/create-pull-request@v6
+      #   with:
+      #     token: ${{ secrets.GITHUB_TOKEN }}
+      #     branch: release-${{ steps.semver-tag-dry.outputs.tag }}
+      #     title: Release ${{ steps.semver-tag-dry.outputs.tag }}
+      #     labels: automerge
+
+      # - name: Check outputs
+      #   if: ${{ steps.cpr.outputs.pull-request-number }}
+      #   run: |
+      #     echo "Pull Request Number - ${{ steps.cpr.outputs.pull-request-number }}"
+      #     echo "Pull Request URL - ${{ steps.cpr.outputs.pull-request-url }}"
+
+      # - name: Merging release PR
+      #   run: gh pr merge --merge --auto "${{ steps.cpr.outputs.pull-request-number }}"
+      #   env:
+      #     GH_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+
+      # Introduce new tag (for real)
+      - name: Bump version and push tag
+        uses: anothrNick/github-tag-action@1.71.0
+        id: semver-tag
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          WITH_V: true
+          INITIAL_VERSION: 1.0.0
+          RELEASE_BRANCHES: master
+          DEFAULT_BUMP: ${{ github.event.inputs.name }}
+          PRERELEASE: false
+          DRY_RUN: false # Not dry
+          VERBOSE: true
+
+      # Run goreleaser to create new binaries
+      - name: Run GoReleaser
+        uses: goreleaser/goreleaser-action@v6
+        with:
+          version: latest
+          args: release --clean
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          RELEASE_VERSION: ${{ steps.semver-tag.outputs.tag }}
+          PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
+          NO_CREATE_CHANGELOG: false
+
+      # Install Python
+      - name: Install Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: 3.x
+
+      # Install Py dependencies
+      - name: Install dependencies
+        run: |
+          python -m pip install --upgrade pip
+          pip install mkdocs-material
+
+      # Build WWW page
+      - name: Build page
+        run: cd www && mkdocs gh-deploy --force
+        env:
+          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/super-linter.yml b/.github/workflows/super-linter.yml
new file mode 100644
--- /dev/null
+++ b/.github/workflows/super-linter.yml
@@ -0,0 +1,42 @@
+---
+name: super-linter
+
+on: # yamllint disable-line rule:truthy
+  push: null
+  pull_request: null
+
+permissions: {} # yamllint disable-line rule:braces
+
+concurrency:
+  group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
+  cancel-in-progress: ${{ !contains(fromJSON('["refs/heads/main", "refs/heads/master"]'), github.ref) }}
+
+jobs:
+  lint:
+    name: Lint Code Base
+    runs-on: ubuntu-latest
+
+    permissions:
+      contents: read
+      packages: read
+      # To report GitHub Actions status checks
+      statuses: write
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+        with:
+          persist-credentials: false
+          # super-linter needs the full git history to get the
+          # list of files that changed across commits
+          fetch-depth: 0
+
+      - name: super-linter
+        uses: super-linter/super-linter/slim@v7
+        env:
+          # To report GitHub Actions status checks
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          FILTER_REGEX_EXCLUDE: "^(/?|/github/workspace/)test-data/"
+          VALIDATE_ALL_CODEBASE: false
+          VALIDATE_JSCPD: false
+          VALIDATE_GO: false
diff --git a/CHANGELOG.howto.md b/CHANGELOG.howto.md
--- a/CHANGELOG.howto.md
+++ b/CHANGELOG.howto.md
@@ -1,9 +1,9 @@
 # How to update CHANGELOG with info on latest release
 
 1. [Install GH CLI](https://github.com/cli/cli?tab=readme-ov-file#installation).
-   * [Configure it](https://cli.github.com/manual/#configuration)
+   - [Configure it](https://cli.github.com/manual/#configuration)
 1. [Install `gh-changelog`](https://github.com/chelnak/gh-changelog?tab=readme-ov-file#installation-and-usage)
-   * Ensure the `.changelog.yml` file is in the root of the repo:
+   - Ensure the `.changelog.yml` file is in the root of the repository:
      ```yaml
      ---
      file_name: CHANGELOG.md.new
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,6 @@
 <!-- markdownlint-disable MD013 MD024 MD043 -->
+<!-- textlint-disable -->
+
 # Changelog
 
 All notable changes to this project will be documented in this file.
@@ -118,7 +120,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 - docs: Update CHANGELOG with `v1.2.0` and `v1.2.1` [#484](https://github.com/warrensbox/terraform-switcher/pull/484) ([yermulnik](https://github.com/yermulnik))
 - fix: Remove duplicate .exe extension added to paths for windows inside symlink, as this is already handled by ConvertExecutableExt [#481](https://github.com/warrensbox/terraform-switcher/pull/481) ([MatthewJohn](https://github.com/MatthewJohn))
 
-
 ## [v1.2.1](https://github.com/warrensbox/terraform-switcher/tree/v1.2.1) - 2024-07-06
 
 [Full Changelog](https://github.com/warrensbox/terraform-switcher/compare/v1.2.0...v1.2.1)
@@ -140,10 +141,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 - docs: Update CHANGELOG with `v1.2.0-alpha2` [#479](https://github.com/warrensbox/terraform-switcher/pull/479) ([yermulnik](https://github.com/yermulnik))
 
-
 ### This release (v1.2.0) containes changes from v1.2.0-alpha2, v1.2.0-alpha1 and v1.2.0-alpha
 
 #### v1.2.0-alpha2
+
 ### Added
 
 - Added ERRORlog-level [#447](https://github.com/warrensbox/terraform-switcher/pull/447) ([MatrixCrawler](https://github.com/MatrixCrawler))
@@ -168,6 +169,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 - added changelog [#415](https://github.com/warrensbox/terraform-switcher/pull/415) ([warrensbox](https://github.com/warrensbox))
 
 #### v1.2.0-alpha1
+
 ### Added
 
 - Add debug logging when successfully obtaining parameter from location… [#464](https://github.com/warrensbox/terraform-switcher/pull/464) ([MatthewJohn](https://github.com/MatthewJohn))
@@ -185,6 +187,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 - Add error return values to signatures of public methods to allow migrating to returning errors rather than Fatals in future [#457](https://github.com/warrensbox/terraform-switcher/pull/457) ([MatthewJohn](https://github.com/MatthewJohn))
 
 #### v1.2.0-alpha
+
 ### Added
 
 - Added ERRORlog-level [#447](https://github.com/warrensbox/terraform-switcher/pull/447) ([MatrixCrawler](https://github.com/MatrixCrawler))
@@ -267,13 +270,13 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 - feat(goreleaser): Enable Release Changelog [#418](https://github.com/warrensbox/terraform-switcher/pull/418) ([yermulnik](https://github.com/yermulnik))
 - added changelog [#415](https://github.com/warrensbox/terraform-switcher/pull/415) ([warrensbox](https://github.com/warrensbox))
 
-## [v1.1.1](https://github.com/warrensbox/terraform-switcher/tree/v1.1.1) - 2024-04-27  
+## [v1.1.1](https://github.com/warrensbox/terraform-switcher/tree/v1.1.1) - 2024-04-27
 
 ### Fixed
 
 - Fix issue related to additional configuration apart from terraform_version_constraint failing #401 [#409](https://github.com/warrensbox/terraform-switcher/pull/409) ([MatrixCrawler](https://github.com/MatrixCrawler))
 - Fix issue related to terraform version constraint in version.tf not being parsed correctly #410 #402 [#403](https://github.com/warrensbox/terraform-switcher/pull/403) ([MatrixCrawler](https://github.com/MatrixCrawler))
-- Fix issue where install.sh is unable to download tfswitch version(s) with 'v' appended to the version number  #394 #413 #413 [#403](https://github.com/warrensbox/terraform-switcher/pull/405) ([yermulnik](https://github.com/yermulnik)) and ([d33psky](https://github.com/d33psky))
+- Fix issue where install.sh is unable to download tfswitch version(s) with 'v' appended to the version number #394 #413 #413 [#403](https://github.com/warrensbox/terraform-switcher/pull/405) ([yermulnik](https://github.com/yermulnik)) and ([d33psky](https://github.com/d33psky))
 
 ## [v1.1.0](https://github.com/warrensbox/terraform-switcher/tree/v1.1.0) - 2024-04-25
 
@@ -333,7 +336,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 ### Other
 
 - fix release - add TAG_CONTEXT [#342](https://github.com/warrensbox/terraform-switcher/pull/342) ([warrensbox](https://github.com/warrensbox))
-- Fixes issues related to  install.sh - #339 [#341](https://github.com/warrensbox/terraform-switcher/pull/341) ([warrensbox](https://github.com/warrensbox))
+- Fixes issues related to install.sh - #339 [#341](https://github.com/warrensbox/terraform-switcher/pull/341) ([warrensbox](https://github.com/warrensbox))
 - fix: Attempt to fix PR335 [#340](https://github.com/warrensbox/terraform-switcher/pull/340) ([yermulnik](https://github.com/yermulnik))
 - #major release -update [#338](https://github.com/warrensbox/terraform-switcher/pull/338) ([warrensbox](https://github.com/warrensbox))
 
@@ -394,7 +397,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ### Other
 
-- Upgrade libraries: cve's   [#258](https://github.com/warrensbox/terraform-switcher/pull/258) ([warrensbox](https://github.com/warrensbox))
+- Upgrade libraries: cve's [#258](https://github.com/warrensbox/terraform-switcher/pull/258) ([warrensbox](https://github.com/warrensbox))
 - Upgrade go libraries to resolve CVE's [#255](https://github.com/warrensbox/terraform-switcher/pull/255) ([jukie](https://github.com/jukie))
 
 ## [0.13.1275](https://github.com/warrensbox/terraform-switcher/releases/tag/0.13.1275) - 2022-06-20
@@ -414,7 +417,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ### Other
 
-- Release 0.13 - Minor release  [#245](https://github.com/warrensbox/terraform-switcher/pull/245) ([warrensbox](https://github.com/warrensbox))
+- Release 0.13 - Minor release [#245](https://github.com/warrensbox/terraform-switcher/pull/245) ([warrensbox](https://github.com/warrensbox))
 - Fix chdirpath for absolute paths [#244](https://github.com/warrensbox/terraform-switcher/pull/244) ([jukie](https://github.com/jukie))
 - Rebase 0.14 master round 3 [#242](https://github.com/warrensbox/terraform-switcher/pull/242) ([jukie](https://github.com/jukie))
 - Use '.' vs full git ref to allow forks or other users to get their own tags [#241](https://github.com/warrensbox/terraform-switcher/pull/241) ([jukie](https://github.com/jukie))
@@ -454,7 +457,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 ### Other
 
 - Fixes Semver issue and M1 installation issue with homebrew [#216](https://github.com/warrensbox/terraform-switcher/pull/216) ([warrensbox](https://github.com/warrensbox))
-- Fixes SemVer issue  [#209](https://github.com/warrensbox/terraform-switcher/pull/209) ([warrensbox](https://github.com/warrensbox))
+- Fixes SemVer issue [#209](https://github.com/warrensbox/terraform-switcher/pull/209) ([warrensbox](https://github.com/warrensbox))
 
 ## [0.13.1201](https://github.com/warrensbox/terraform-switcher/releases/tag/0.13.1201) - 2021-11-28
 
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -8,19 +8,19 @@ In the interest of fostering an open and welcoming environment, we as contributo
 
 Examples of behavior that contributes to creating a positive environment include:
 
-* Using welcoming and inclusive language
-* Being respectful of differing viewpoints and experiences
-* Gracefully accepting constructive criticism
-* Focusing on what is best for the community
-* Showing empathy towards other community members
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
 
 Examples of unacceptable behavior by participants include:
 
-* The use of sexualized language or imagery and unwelcome sexual attention or advances
-* Trolling, insulting/derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or electronic address, without explicit permission
-* Other conduct which could reasonably be considered inappropriate in a professional setting
+- The use of sexualized language or imagery and unwelcome sexual attention or advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a professional setting
 
 ## Our Responsibilities
 
@@ -30,11 +30,11 @@ Project maintainers have the right and responsibility to remove, edit, or reject
 
 ## Scope
 
-This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
+This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
 
 ## Enforcement
 
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@warrensbox.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [support@warrensbox.com](mailto:support@warrensbox.com). The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
 
 Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,3 +1,5 @@
+<!-- markdownlint-disable MD041 -->
+
 [![Build Status](https://github.com/warrensbox/terraform-switcher/actions/workflows/build.yml/badge.svg)](https://github.com/warrensbox/terraform-switcher/actions/workflows/build.yml)
 [![Go Report Card](https://goreportcard.com/badge/github.com/warrensbox/terraform-switcher)](https://goreportcard.com/report/github.com/warrensbox/terraform-switcher)
 ![GitHub Release](https://img.shields.io/github/v/release/warrensbox/terraform-switcher)
@@ -8,7 +10,7 @@
 
 <img style="text-align:center" src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/smallerlogo.png" alt="drawing" width="120" height="130"/>
 
-The `tfswitch` command line tool lets you switch between different versions of [Terraform](https://www.terraform.io/).  
+The `tfswitch` command-line tool lets you switch between different versions of [Terraform](https://www.terraform.io/).  
 If you do not have a particular version of Terraform installed, `tfswitch` will download and verify the version you desire.  
 The installation is minimal and easy.  
 Once installed, simply select the version you require from the dropdown and start using Terraform.
@@ -36,7 +38,7 @@ See the [release page](https://github.com/warrensbox/terraform-switcher/releases
 
 ## Homebrew
 
-For macOS or various Linux distributions, Homebrew offers the simplest installation process. <a href="https://brew.sh/" target="_blank">If you do not have homebrew installed, click here</a>.
+For macOS or various Linux distributions, Homebrew offers the simplest installation process. <a href="https://brew.sh/" target="_blank">If you do not have Homebrew installed, click here</a>.
 
 ```shell
 brew install warrensbox/tap/tfswitch
@@ -73,7 +75,7 @@ See [our installation documentation](https://tfswitch.warrensbox.com/Installatio
 >
 > Please change any automated implementations relying on the `tfswitch` version string.
 >
-> **Old version string:** `0.1.2412`
+> **Old version string:** `0.1.2412`  
 > **New version string:** `v1.0.3`
 
 [Having trouble installing](https://tfswitch.warrensbox.com/Troubleshoot/)
@@ -99,8 +101,8 @@ See step-by-step instructions on how to contribute here: [Contribute](https://tf
 
 ## Additional Info
 
-See how to [*upgrade* and *uninstall*](https://tfswitch.warrensbox.com/Upgrade-or-Uninstall/) or [*troubleshoot*](https://tfswitch.warrensbox.com/Troubleshoot/)
+See how to [_upgrade_ and _uninstall_](https://tfswitch.warrensbox.com/Upgrade-or-Uninstall/) or [_troubleshoot_](https://tfswitch.warrensbox.com/Troubleshoot/)
 
 ## Issues
 
-Please open *issues* here: [New Issue](https://github.com/warrensbox/terraform-switcher/issues)
+Please open _issues_ here: [New Issue](https://github.com/warrensbox/terraform-switcher/issues)
diff --git a/go.mod b/go.mod
--- a/go.mod
+++ b/go.mod
@@ -10,7 +10,7 @@ require (
 	github.com/gookit/slog v0.5.8
 	github.com/hashicorp/go-version v1.7.0
 	github.com/hashicorp/hcl/v2 v2.23.0
-	github.com/hashicorp/terraform-config-inspect v0.0.0-20240509232506-4708120f8f30
+	github.com/hashicorp/terraform-config-inspect v0.0.0-20250203082807-efaa306e97b4
 	github.com/manifoldco/promptui v0.9.0
 	github.com/mitchellh/go-homedir v1.1.0
 	github.com/pborman/getopt v1.1.0
@@ -30,31 +30,31 @@ require (
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/fsnotify/fsnotify v1.8.0 // indirect
 	github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
-	github.com/google/go-cmp v0.6.0 // indirect
+	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/gookit/goutil v0.6.18 // indirect
 	github.com/gookit/gsr v0.1.0 // indirect
-	github.com/hashicorp/hcl v1.0.1-vault-5 // indirect
+	github.com/hashicorp/hcl v1.0.1-vault-7 // indirect
 	github.com/mitchellh/go-wordwrap v1.0.1 // indirect
 	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
 	github.com/rogpeppe/go-internal v1.12.0 // indirect
-	github.com/sagikazarmark/locafero v0.7.0 // indirect
+	github.com/sagikazarmark/locafero v0.9.0 // indirect
 	github.com/sourcegraph/conc v0.3.0 // indirect
-	github.com/spf13/afero v1.12.0 // indirect
+	github.com/spf13/afero v1.14.0 // indirect
 	github.com/spf13/cast v1.7.1 // indirect
 	github.com/spf13/pflag v1.0.6 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
-	github.com/zclconf/go-cty v1.14.4 // indirect
+	github.com/zclconf/go-cty v1.16.2 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect
-	golang.org/x/mod v0.17.0 // indirect
+	golang.org/x/mod v0.24.0 // indirect
 	golang.org/x/sync v0.12.0 // indirect
 	golang.org/x/term v0.30.0 // indirect
 	golang.org/x/text v0.23.0 // indirect
-	golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
+	golang.org/x/tools v0.31.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/go.sum b/go.sum
--- a/go.sum
+++ b/go.sum
@@ -30,8 +30,8 @@ github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
 github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
 github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
 github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
-github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
-github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
 github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0=
 github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w=
 github.com/gookit/goutil v0.6.18 h1:MUVj0G16flubWT8zYVicIuisUiHdgirPAkmnfD2kKgw=
@@ -42,12 +42,12 @@ github.com/gookit/slog v0.5.8 h1:XZCeHLQvvOZWcSUDZcqxXITsL9+d1ESsKZoASBmK1lI=
 github.com/gookit/slog v0.5.8/go.mod h1:s0ViFOY/IgUuT4MDPF0l9x5/npcciy8pL4xwWZadnoc=
 github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
 github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
-github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM=
-github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
+github.com/hashicorp/hcl v1.0.1-vault-7 h1:ag5OxFVy3QYTFTJODRzTKVZ6xvdfLLCA1cy/Y6xGI0I=
+github.com/hashicorp/hcl v1.0.1-vault-7/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM=
 github.com/hashicorp/hcl/v2 v2.23.0 h1:Fphj1/gCylPxHutVSEOf2fBOh1VE4AuLV7+kbJf3qos=
 github.com/hashicorp/hcl/v2 v2.23.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA=
-github.com/hashicorp/terraform-config-inspect v0.0.0-20240509232506-4708120f8f30 h1:0qwr2oZy9mIIJMWh7W9NTHLWGMbEF5KEQ+QqM9hym34=
-github.com/hashicorp/terraform-config-inspect v0.0.0-20240509232506-4708120f8f30/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI=
+github.com/hashicorp/terraform-config-inspect v0.0.0-20250203082807-efaa306e97b4 h1:6zYoI+NGpRPo0UjbnJfmqqTFcTEKvbv77h0ZcgeLXJs=
+github.com/hashicorp/terraform-config-inspect v0.0.0-20250203082807-efaa306e97b4/go.mod h1:Gz/z9Hbn+4KSp8A2FBtNszfLSdT2Tn/uAKGuVqqWmDI=
 github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -71,12 +71,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
 github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/sagikazarmark/locafero v0.7.0 h1:5MqpDsTGNDhY8sGp0Aowyf0qKsPrhewaLSsFaodPcyo=
-github.com/sagikazarmark/locafero v0.7.0/go.mod h1:2za3Cg5rMaTMoG/2Ulr9AwtFaIppKXTRYnozin4aB5k=
+github.com/sagikazarmark/locafero v0.9.0 h1:GbgQGNtTrEmddYDSAH9QLRyfAHY12md+8YFTqyMTC9k=
+github.com/sagikazarmark/locafero v0.9.0/go.mod h1:UBUyz37V+EdMS3hDF3QWIiVr/2dPrx49OMO0Bn0hJqk=
 github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
 github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
-github.com/spf13/afero v1.12.0 h1:UcOPyRBYczmFn6yvphxkn9ZEOY65cpwGKb5mL36mrqs=
-github.com/spf13/afero v1.12.0/go.mod h1:ZTlWwG4/ahT8W7T0WQ5uYmjI9duaLQGy3Q2OAl4sk/4=
+github.com/spf13/afero v1.14.0 h1:9tH6MapGnn/j0eb0yIXiLjERO8RB6xIVZRDCX7PtqWA=
+github.com/spf13/afero v1.14.0/go.mod h1:acJQ8t0ohCGuMN3O+Pv0V0hgMxNYDlvdk+VTfyZmbYo=
 github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
 github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
 github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
@@ -92,8 +92,8 @@ github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyC
 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-github.com/zclconf/go-cty v1.14.4 h1:uXXczd9QDGsgu0i/QFR/hzI5NYCHLf6NQw/atrbnhq8=
-github.com/zclconf/go-cty v1.14.4/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
+github.com/zclconf/go-cty v1.16.2 h1:LAJSwc3v81IRBZyUVQDUdZ7hs3SYs9jv0eZJDWHD/70=
+github.com/zclconf/go-cty v1.16.2/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE=
 github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo=
 github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM=
 go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
@@ -106,8 +106,8 @@ golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znF
 golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -143,8 +143,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
-golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
+golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/install.sh b/install.sh
--- a/install.sh
+++ b/install.sh
@@ -1,18 +1,17 @@
 #!/bin/sh
 set -e
 
-
 usage() {
   this=$1
   cat <<EOF
-$this: download go binaries for warrensbox/tfswitch
+$this: Download Go binaries for $OWNER/$BINARY
+
+Usage: $this [-b dir] [-d] [tag]
+  -b Sets installation directory. Defaults to ./bin
+  -d Turns on debug logging
 
-Usage: $this [-b] bindir [-d] [tag]
-  -b sets bindir or installation directory, Defaults to ./bin
-  -d turns on debug logging
-   [tag] is a tag from
-   https://github.com/warrensbox/terraform-switcher/releases
-   If tag is missing, then the latest will be used.
+  [tag] Is a tag from https://github.com/$PREFIX/releases
+        If tag is missing, then the latest will be used.
 
 EOF
   exit 2
@@ -46,7 +45,8 @@ execute() {
   srcdir="${tmpdir}"
   (cd "${tmpdir}" && untar "${TARBALL}")
   install -d "${BINDIR}"
-  for binexe in "tfswitch" ; do
+  # shellcheck disable=SC2043,SC2066 # We're good with this loop to only ever run once
+  for binexe in "$BINARY"; do
     if [ "$OS" = "windows" ]; then
       binexe="${binexe}.exe"
     fi
@@ -90,7 +90,7 @@ adjust_format() {
   # change format (tar.gz or zip) based on ARCH
   case ${OS} in
     # zip archives for Windows appeared in tfswitch v1.3.1
-    windows) [ "$REALTAG" ">" "v1.3.0" ] && FORMAT=zip ;;
+    windows) expr "$REALTAG" \> "v1.3.0" >/dev/null && FORMAT=zip ;;
   esac
   true
 }
@@ -118,6 +118,7 @@ echoerr() {
   echo "$@" 1>&2
 }
 log_prefix() {
+  # shellcheck disable=SC2317 # (info): Command appears to be unreachable
   echo "$0"
 }
 _logp=6
@@ -179,7 +180,7 @@ uname_arch() {
     armv6*) arch="armv6" ;;
     armv7*) arch="armv7" ;;
   esac
-  echo ${arch}
+  echo "${arch}"
 }
 uname_os_check() {
   os=$(uname_os)
@@ -343,8 +344,8 @@ End of functions from https://github.com/client9/shlib
 EOF
 
 PROJECT_NAME="terraform-switcher"
-OWNER=warrensbox
-REPO="terraform-switcher"
+OWNER="warrensbox"
+REPO="$PROJECT_NAME"
 BINARY=tfswitch
 FORMAT=tar.gz
 OS=$(uname_os)
@@ -353,10 +354,10 @@ PREFIX="$OWNER/$REPO"
 
 # use in logging routines
 log_prefix() {
-	echo "$PREFIX"
+  echo "$PREFIX"
 }
 PLATFORM="${OS}/${ARCH}"
-GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
+GITHUB_DOWNLOAD=https://github.com/$PREFIX/releases/download
 
 uname_os_check "$OS"
 uname_arch_check "$ARCH"
diff --git a/lib/checksum.go b/lib/checksum.go
--- a/lib/checksum.go
+++ b/lib/checksum.go
@@ -9,6 +9,7 @@ import (
 	"path/filepath"
 	"strings"
 
+	//nolint:staticcheck // TODO: https://github.com/warrensbox/terraform-switcher/issues/439
 	"golang.org/x/crypto/openpgp"
 )
 
diff --git a/lib/command.go b/lib/command.go
--- a/lib/command.go
+++ b/lib/command.go
@@ -1,13 +1,15 @@
 package lib
 
 import (
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"runtime"
 	"strings"
 )
 
+// string `windows` has 12 occurrences, make it a constant (goconst)
+const windows = "windows"
+
 // Command : type string
 type Command struct {
 	name string
@@ -42,11 +44,11 @@ func isExecutable(path string) bool {
 		return false
 	}
 
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == windows {
 		return true
 	}
 
-	if fileInfo.Mode()&0111 != 0 {
+	if fileInfo.Mode()&0o111 != 0 {
 		return true
 	}
 
@@ -61,7 +63,7 @@ func (cmd *Command) Find() func() string {
 			if !isDir(p) {
 				continue
 			}
-			fileList, err := ioutil.ReadDir(p)
+			fileList, err := os.ReadDir(p)
 			if err != nil {
 				continue
 			}
diff --git a/lib/common.go b/lib/common.go
--- a/lib/common.go
+++ b/lib/common.go
@@ -12,7 +12,7 @@ func checkFileExist(file string) bool {
 
 func createFile(path string) {
 	// detect if file exists
-	var _, err = os.Stat(path)
+	_, err := os.Stat(path)
 
 	// create file if not exists
 	if os.IsNotExist(err) {
@@ -28,7 +28,10 @@ func createFile(path string) {
 }
 
 func cleanUp(path string) {
-	removeContents(path)
+	err := removeContents(path)
+	if err != nil {
+		logger.Error(err)
+	}
 	removeFiles(path)
 }
 
diff --git a/lib/defaults.go b/lib/defaults.go
--- a/lib/defaults.go
+++ b/lib/defaults.go
@@ -7,5 +7,5 @@ const (
 	pubKeySuffix              = ".asc"
 	recentFile                = "RECENT"
 	tfDarwinArm64StartVersion = "1.0.2"
-	DefaultProductId          = "terraform"
+	DefaultProductId          = "terraform" // nolint:revive // FIXME: var-naming: const DefaultProductId should be DefaultProductID (revive)
 )
diff --git a/lib/download.go b/lib/download.go
--- a/lib/download.go
+++ b/lib/download.go
@@ -19,8 +19,11 @@ func DownloadFromURL(installLocation, mirrorURL, tfversion, versionPrefix, goos,
 func DownloadProductFromURL(product Product, installLocation, mirrorURL, tfversion, versionPrefix, goos, goarch string) (string, error) {
 	var wg sync.WaitGroup
 	defer wg.Done()
+	// nolint:revive // FIXME: var-naming: var zipUrl should be zipURL (revive)
 	zipUrl := mirrorURL + "/" + versionPrefix + tfversion + "_" + goos + "_" + goarch + ".zip"
+	// nolint:revive // FIXME: var-naming: var hashUrl should be hashURL (revive)
 	hashUrl := mirrorURL + "/" + versionPrefix + tfversion + "_SHA256SUMS"
+	// nolint:revive // FIXME: var-naming: var hashSignatureUrl should be hashSignatureURL (revive)
 	hashSignatureUrl := mirrorURL + "/" + versionPrefix + tfversion + "_SHA256SUMS." + product.GetShaSignatureSuffix()
 
 	pubKeyFilename, err := downloadPublicKey(product, installLocation, &wg)
@@ -99,7 +102,7 @@ func downloadFromURL(installLocation string, url string, wg *sync.WaitGroup) (st
 	fileName := tokens[len(tokens)-1]
 	logger.Infof("Downloading to %q", filepath.Join(installLocation, "/", fileName))
 
-	response, err := http.Get(url)
+	response, err := http.Get(url) // nolint:gosec // `url' is expected to be variable
 	if err != nil {
 		logger.Errorf("Error downloading %s: %v", url, err)
 		return "", err
diff --git a/lib/files.go b/lib/files.go
--- a/lib/files.go
+++ b/lib/files.go
@@ -25,15 +25,10 @@ func RenameFile(src string, dest string) {
 
 // RemoveFiles : remove file
 func RemoveFiles(src string) {
-	files, err := filepath.Glob(src)
-	if err != nil {
-		panic(err)
-	}
-	for _, f := range files {
-		if err := os.Remove(f); err != nil {
-			panic(err)
-		}
-	}
+	// Keep both identical functions for backward compatibility
+	// FIXME: need to plan deprecation of either of them
+	// 09-Mar-2025
+	removeFiles(src)
 }
 
 // CheckFileExist : check if file exist in directory
@@ -71,7 +66,7 @@ func Unzip(src string, dest string, fileToUnzipSlice ...string) ([]string, error
 	}
 	var unzipWaitGroup sync.WaitGroup
 	for _, f := range reader.File {
-		// Only extract the main binary binary
+		// Only extract the main binary
 		// from the archive, ignoring LICENSE and other files
 		if f.Name != ConvertExecutableExt(fileToUnzip) {
 			continue
@@ -80,10 +75,10 @@ func Unzip(src string, dest string, fileToUnzipSlice ...string) ([]string, error
 		unzipWaitGroup.Add(1)
 		unzipErr := unzipFile(f, destination, &unzipWaitGroup)
 		if unzipErr != nil {
-			logger.Fatalf("Error unzipping %v", unzipErr)
-		} else {
-			filenames = append(filenames, filepath.Join(destination, f.Name))
+			return nil, fmt.Errorf("Error unzipping: %v", unzipErr)
 		}
+		// nolint:gosec // The "G305: File traversal when extracting zip/tar archive" is handled by unzipFile()
+		filenames = append(filenames, filepath.Join(destination, f.Name))
 	}
 	logger.Debug("Waiting for deferred functions")
 	unzipWaitGroup.Wait()
@@ -187,10 +182,8 @@ func CheckDirHasTGBin(dir, prefix string) bool {
 	if err != nil {
 		logger.Fatal(err)
 	}
-	res := []string{}
 	for _, f := range files {
 		if !f.IsDir() && strings.HasPrefix(f.Name(), prefix) {
-			res = append(res, filepath.Join(dir, f.Name()))
 			exist = true
 		}
 	}
@@ -216,7 +209,7 @@ func CheckIsDir(dir string) bool {
 	fi, err := os.Stat(dir)
 
 	if err != nil {
-		logger.Debugf("Error checking %q: %w", dir, err)
+		logger.Debugf("Error checking %q: %v", dir, err)
 		return false
 	} else if !fi.IsDir() {
 		logger.Debugf("The %q is not a directory", dir)
@@ -241,7 +234,7 @@ func GetFileName(configfile string) string {
 func GetCurrentDirectory() string {
 	dir, err := os.Getwd() // get current directory
 	if err != nil {
-		logger.Fatalf("Failed to get current directory %v", err)
+		logger.Fatalf("Failed to get current directory: %v", err)
 	}
 	return dir
 }
@@ -250,7 +243,7 @@ func GetCurrentDirectory() string {
 func GetHomeDirectory() string {
 	homedir, err := homedir.Dir()
 	if err != nil {
-		logger.Fatalf("Failed to get user's home directory %v", err)
+		logger.Fatalf("Failed to get user's home directory: %v", err)
 	}
 	return homedir
 }
@@ -258,7 +251,7 @@ func GetHomeDirectory() string {
 func unzipFile(f *zip.File, destination string, wg *sync.WaitGroup) error {
 	defer wg.Done()
 	// 1. Check if file paths are not vulnerable to Zip Slip
-	filePath := filepath.Join(destination, f.Name)
+	filePath := filepath.Join(destination, f.Name) // nolint:gosec // The "G305: File traversal when extracting zip/tar archive" is handled below
 	if !strings.HasPrefix(filePath, filepath.Clean(destination)+string(os.PathSeparator)) {
 		return fmt.Errorf("Invalid file path: %q", filePath)
 	}
@@ -279,6 +272,7 @@ func unzipFile(f *zip.File, destination string, wg *sync.WaitGroup) error {
 	// 3. Create a destination file for unzipped content
 	destinationFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
 	defer func(destinationFile *os.File) {
+		logger.Debugf("Closing destination file handler %q", destinationFile.Name())
 		_ = destinationFile.Close()
 	}(destinationFile)
 	if err != nil {
@@ -288,19 +282,33 @@ func unzipFile(f *zip.File, destination string, wg *sync.WaitGroup) error {
 	// 4. Unzip the content of a file and copy it to the destination file
 	zippedFile, err := f.Open()
 	defer func(zippedFile io.ReadCloser) {
+		logger.Debugf("Closing zipped file handler %q", f.Name)
 		_ = zippedFile.Close()
 	}(zippedFile)
 	if err != nil {
 		return err
 	}
 
-	logger.Debugf("Extracting File %q", destinationFile.Name())
-	if _, err := io.Copy(destinationFile, zippedFile); err != nil {
-		return err
+	logger.Debugf("Extracting file %q to %q", f.Name, destinationFile.Name())
+	// Prevent the "G110: Potential DoS vulnerability via decompression bomb (gosec)"
+	totalCopied := int64(0)
+	maxSize := int64(1024 * 1024 * 1024) // 1 GB
+	for {
+		copied, err := io.CopyN(destinationFile, zippedFile, 1024*1024)
+		totalCopied += copied
+		if totalCopied%(10*1024*1024) == 0 { // Print stats every 10 MB
+			logger.Debugf("Size copied so far: %3.d MB\r", totalCopied/1024/1024)
+		}
+		if err != nil {
+			if err == io.EOF {
+				logger.Debugf("Total size copied: %4.d MB\r", totalCopied/1024/1024)
+				break
+			}
+			return err
+		}
+		if totalCopied > maxSize {
+			return fmt.Errorf("file %q is too large (> %d MB)", f.Name, maxSize/1024/1024)
+		}
 	}
-	logger.Debugf("Closing destination file handler %q", destinationFile.Name())
-	_ = destinationFile.Close()
-	logger.Debugf("Closing zipped file handler %q", f.Name)
-	_ = zippedFile.Close()
 	return nil
 }
diff --git a/lib/install.go b/lib/install.go
--- a/lib/install.go
+++ b/lib/install.go
@@ -16,6 +16,8 @@ import (
 var installLocation = "/tmp"
 
 // initialize : removes existing symlink to terraform binary based on provided binPath
+//
+//nolint:unused // FIXME: Function is not used 10-Mar-2025
 func initialize(binPath string) {
 	/* find terraform binary location if terraform is already installed*/
 	cmd := NewCommand(binPath)
@@ -27,12 +29,14 @@ func initialize(binPath string) {
 		binPath = path
 	}
 
-	/* check if current symlink to terraform binary exist */
+	/* check if current symlink to terraform binary exists */
 	symlinkExist := CheckSymlink(binPath)
 
-	/* remove current symlink if exist*/
+	/* remove current symlink if exists */
 	if symlinkExist {
-		RemoveSymlink(binPath)
+		if err := RemoveSymlink(binPath); err != nil {
+			logger.Errorf("Error removing symlink: %v", err)
+		}
 	}
 }
 
@@ -42,7 +46,7 @@ func GetInstallLocation(installPath string) string {
 	/* set installation location */
 	installLocation = filepath.Join(installPath, InstallDir)
 
-	/* Create local installation directory if it does not exist */
+	/* Create local installation directory if it does not exists */
 	createDirIfNotExist(installLocation)
 	return installLocation
 }
@@ -72,11 +76,14 @@ func install(product Product, tfversion, binPath, installPath, mirrorURL, goarch
 
 	// If the requested version had not been downloaded before
 	// Set list all true - all versions including beta and rc will be displayed
-	tflist, _ := getTFList(mirrorURL, true) // Get list of versions
+	tflist, errTFList := getTFList(mirrorURL, true) // Get list of versions
+	if errTFList != nil {
+		return fmt.Errorf("Error getting list of %s versions from %q: %v", product.GetName(), mirrorURL, errTFList)
+	}
 
 	// Check if version exists before downloading it
 	if !versionExist(tfversion, tflist) {
-		return fmt.Errorf("Provided %s version does not exist: %q.\n\tTry `tfswitch -l` to see all available versions", product.GetId(), tfversion)
+		return fmt.Errorf("Provided %s version does not exist: %q.\n\tTry `tfswitch -l` to see all available versions", product.GetName(), tfversion)
 	}
 
 	if goarch != runtime.GOARCH {
@@ -86,8 +93,14 @@ func install(product Product, tfversion, binPath, installPath, mirrorURL, goarch
 	goos := runtime.GOOS
 
 	// Terraform darwin arm64 comes with 1.0.2 and next version
-	tfver, _ := version.NewVersion(tfversion)
-	tf102, _ := version.NewVersion(tfDarwinArm64StartVersion)
+	tfver, tfverErr := version.NewVersion(tfversion)
+	if tfverErr != nil {
+		return fmt.Errorf("Error parsing %q version: %v", tfversion, tfverErr)
+	}
+	tf102, tf102Err := version.NewVersion(tfDarwinArm64StartVersion)
+	if tf102Err != nil {
+		return fmt.Errorf("Error parsing %q version: %v", tfDarwinArm64StartVersion, tf102Err)
+	}
 	if goos == "darwin" && goarch == "arm64" && tfver.LessThan(tf102) {
 		goarch = "amd64"
 	}
@@ -140,12 +153,13 @@ func switchToVersion(product Product, tfversion string, binPath string, installP
 
 // ConvertExecutableExt : convert executable with local OS extension
 func ConvertExecutableExt(fpath string) string {
+	const winExt = ".exe"
 	switch runtime.GOOS {
-	case "windows":
-		if filepath.Ext(fpath) == ".exe" {
+	case windows:
+		if filepath.Ext(fpath) == winExt {
 			return fpath
 		}
-		return fpath + ".exe"
+		return fpath + winExt
 	default:
 		return fpath
 	}
@@ -154,6 +168,8 @@ func ConvertExecutableExt(fpath string) string {
 // installableBinLocation : Checks if terraform is installable in the location provided by the user.
 // If not, create $HOME/bin. Ask users to add  $HOME/bin to $PATH and return $HOME/bin as install location
 // Deprecated: This function has been deprecated and will be removed in v2.0.0
+//
+//nolint:unused // Function is deprecated
 func installableBinLocation(product Product, userBinPath string) string {
 	homedir := GetHomeDirectory()         // get user's home directory
 	binDir := Path(userBinPath)           // get path directory from binary path
@@ -162,11 +178,12 @@ func installableBinLocation(product Product, userBinPath string) string {
 	if binPathExist { // if bin path exist - check if we can write to it
 
 		binPathWritable := false // assume bin path is not writable
-		if runtime.GOOS != "windows" {
+		if runtime.GOOS != windows {
 			binPathWritable = CheckDirWritable(binDir) // check if is writable on ( only works on LINUX)
 		}
 
-		// IF: "/usr/local/bin" or `custom bin path` provided by user is non-writable, (binPathWritable == false), we will attempt to install terraform at the ~/bin location. See ELSE
+		// IF: "/usr/local/bin" or `custom bin path` provided by user is non-writable, (binPathWritable == false),
+		// we will attempt to install terraform at the ~/bin location. See ELSE
 		if !binPathWritable {
 			homeBinDir := filepath.Join(homedir, "bin")
 			if !CheckDirExist(homeBinDir) { // if ~/bin exist, install at ~/bin/terraform
@@ -178,9 +195,9 @@ func installableBinLocation(product Product, userBinPath string) string {
 			logger.Infof("Installing %s at %q", product.GetName(), homeBinDir)
 			return filepath.Join(homeBinDir, product.GetExecutableName())
 
-		} else { // ELSE: the "/usr/local/bin" or custom path provided by user is writable, we will return installable location
-			return filepath.Join(userBinPath)
 		}
+		// ELSE: the "/usr/local/bin" or custom path provided by user is writable, we will return installable location
+		return userBinPath
 	}
 
 	logger.Fatalf("Binary path (%q) does not exist. Manually create bin directory %q and try again", userBinPath, binDir)
@@ -193,15 +210,21 @@ func installableBinLocation(product Product, userBinPath string) string {
 // Deprecated: This function has been deprecated in favor of InstallLatestProductVersion and will be removed in v2.0.0
 func InstallLatestVersion(dryRun bool, customBinaryPath, installPath, mirrorURL, arch string) {
 	product := getLegacyProduct()
+	//nolint:errcheck // Function is deprecated
 	InstallLatestProductVersion(product, dryRun, customBinaryPath, installPath, mirrorURL, arch)
 }
 
 // InstallLatestProductVersion install latest stable tf version
 func InstallLatestProductVersion(product Product, dryRun bool, customBinaryPath, installPath, mirrorURL, arch string) error {
-	tfversion, _ := getTFLatest(mirrorURL)
+	tfversion, err := getTFLatest(mirrorURL)
+	if err != nil {
+		return fmt.Errorf("Error getting latest %s version from %q: %v", product.GetName(), mirrorURL, err)
+	}
+
 	if !dryRun {
 		return install(product, tfversion, customBinaryPath, installPath, mirrorURL, arch)
 	}
+
 	return nil
 }
 
@@ -210,6 +233,7 @@ func InstallLatestProductVersion(product Product, dryRun bool, customBinaryPath,
 // Deprecated: This function has been deprecated in favor of InstallLatestProductImplicitVersion and will be removed in v2.0.0
 func InstallLatestImplicitVersion(dryRun bool, requestedVersion, customBinaryPath, installPath, mirrorURL, arch string, preRelease bool) {
 	product := getLegacyProduct()
+	//nolint:errcheck // Function is deprecated
 	InstallLatestProductImplicitVersion(product, dryRun, requestedVersion, customBinaryPath, installPath, mirrorURL, arch, preRelease)
 }
 
@@ -222,7 +246,9 @@ func InstallLatestProductImplicitVersion(product Product, dryRun bool, requested
 	}
 	tfversion, err := getTFLatestImplicit(mirrorURL, preRelease, requestedVersion)
 	if err == nil && tfversion != "" && !dryRun {
-		install(product, tfversion, customBinaryPath, installPath, mirrorURL, arch)
+		if err := install(product, tfversion, customBinaryPath, installPath, mirrorURL, arch); err != nil {
+			return fmt.Errorf("Error installing %s version %q: %v", product.GetName(), tfversion, err)
+		}
 		return nil
 	}
 	PrintInvalidMinorTFVersion()
@@ -234,6 +260,7 @@ func InstallLatestProductImplicitVersion(product Product, dryRun bool, requested
 // Deprecated: This function has been deprecated in favor of InstallProductVersion and will be removed in v2.0.0
 func InstallVersion(dryRun bool, version, customBinaryPath, installPath, mirrorURL, arch string) {
 	product := getLegacyProduct()
+	//nolint:errcheck // Function is deprecated
 	InstallProductVersion(product, dryRun, version, customBinaryPath, installPath, mirrorURL, arch)
 }
 
@@ -244,13 +271,11 @@ func InstallProductVersion(product Product, dryRun bool, version, customBinaryPa
 		if validVersionFormat(version) {
 			requestedVersion := version
 			return install(product, requestedVersion, customBinaryPath, installPath, mirrorURL, arch)
-		} else {
-			PrintInvalidTFVersion()
-			return fmt.Errorf("Argument must be a valid %s version", product.GetName())
 		}
-	} else {
-		logger.Infof("[DRY-RUN] Would have attempted to install version %q", version)
+		PrintInvalidTFVersion()
+		return fmt.Errorf("Argument must be a valid %s version", product.GetName())
 	}
+	logger.Infof("[DRY-RUN] Would have attempted to install version %q", version)
 	return nil
 }
 
@@ -261,6 +286,7 @@ func InstallProductVersion(product Product, dryRun bool, version, customBinaryPa
 // Deprecated: This function has been deprecated in favor of InstallProductOption and will be removed in v2.0.0
 func InstallOption(listAll, dryRun bool, customBinaryPath, installPath, mirrorURL, arch string) {
 	product := getLegacyProduct()
+	//nolint:errcheck // Function is deprecated
 	InstallProductOption(product, listAll, dryRun, customBinaryPath, installPath, mirrorURL, arch)
 }
 
@@ -275,9 +301,10 @@ type VersionSelector struct {
 func InstallProductOption(product Product, listAll, dryRun bool, customBinaryPath, installPath, mirrorURL, arch string) error {
 	var selectVersions []VersionSelector
 
-	var versionMap map[string]bool = make(map[string]bool)
+	versionMap := make(map[string]bool)
 
 	// Add recent versions
+	//nolint:errcheck // getRecentVersions always returns nil error %-/
 	recentVersions, _ := getRecentVersions(installPath, product)
 	for _, version := range recentVersions {
 		selectVersions = append(selectVersions, VersionSelector{
@@ -288,7 +315,10 @@ func InstallProductOption(product Product, listAll, dryRun bool, customBinaryPat
 	}
 
 	// Add all versions
-	tfList, _ := getTFList(mirrorURL, listAll)
+	tfList, errTFList := getTFList(mirrorURL, listAll)
+	if errTFList != nil {
+		return fmt.Errorf("Error getting list of %s versions from %q: %v", product.GetName(), mirrorURL, errTFList)
+	}
 	for _, version := range tfList {
 		if !versionMap[version] {
 			selectVersions = append(selectVersions, VersionSelector{
@@ -322,14 +352,14 @@ func InstallProductOption(product Product, listAll, dryRun bool, customBinaryPat
 		if errPrompt.Error() == "^C" {
 			// Cancel execution
 			return fmt.Errorf("user interrupt")
-		} else {
-			return fmt.Errorf("prompt failed %v", errPrompt)
 		}
+		return fmt.Errorf("prompt failed %v", errPrompt)
 	}
+
 	if !dryRun {
 		return install(product, selectVersions[selectedItx].Version, customBinaryPath, installPath, mirrorURL, arch)
-	} else {
-		logger.Infof("[DRY-RUN] Would have attempted to install version %q", selectVersions[selectedItx].Version)
 	}
+
+	logger.Infof("[DRY-RUN] Would have attempted to install version %q", selectVersions[selectedItx].Version)
 	return nil
 }
diff --git a/lib/list_versions.go b/lib/list_versions.go
--- a/lib/list_versions.go
+++ b/lib/list_versions.go
@@ -23,7 +23,10 @@ func getVersionsFromBody(body string, preRelease bool, tfVersionList *tfVersionL
 		// without the ending '"' pre-release folders would be tried and break.
 		semver = `\/?(\d+\.\d+\.\d+)\/?"`
 	}
-	r, _ := regexp.Compile(semver)
+	r, err := regexp.Compile(semver)
+	if err != nil {
+		logger.Fatalf("Error compiling %q regex: %v", semver, err)
+	}
 
 	matches := r.FindAllString(body, -1)
 	if matches == nil {
@@ -60,7 +63,10 @@ func getTFLatest(mirrorURL string) (string, error) {
 	}
 	// Getting versions from body; should return match /X.X.X/ where X is a number
 	semver := `\/?(\d+\.\d+\.\d+)\/?"`
-	r, _ := regexp.Compile(semver)
+	r, errSemVer := regexp.Compile(semver)
+	if errSemVer != nil {
+		return "", fmt.Errorf("Error compiling %q regex: %v", semver, errSemVer)
+	}
 	bodyLines := strings.Split(result, "\n")
 	for i := range result {
 		if r.MatchString(bodyLines[i]) {
@@ -76,15 +82,15 @@ func getTFLatest(mirrorURL string) (string, error) {
 func getTFLatestImplicit(mirrorURL string, preRelease bool, version string) (string, error) {
 	if preRelease {
 		// TODO: use getTFList() instead of getTFURLBody
-		body, error := getTFURLBody(mirrorURL)
-		if error != nil {
-			return "", error
+		body, err := getTFURLBody(mirrorURL)
+		if err != nil {
+			return "", err
 		}
 		// Getting versions from body; should return match /X.X.X-@/ where X is a number,@ is a word character between a-z or A-Z
 		semver := fmt.Sprintf(`\/?(%s{1}\.\d+\-[a-zA-z]+\d*)\/?"`, version)
-		r, err := regexp.Compile(semver)
-		if err != nil {
-			return "", err
+		r, errReSemVer := regexp.Compile(semver)
+		if errReSemVer != nil {
+			return "", errReSemVer
 		}
 		versions := strings.Split(body, "\n")
 		for i := range versions {
@@ -96,7 +102,11 @@ func getTFLatestImplicit(mirrorURL string, preRelease bool, version string) (str
 		}
 	} else if !preRelease {
 		listAll := false
-		tflist, _ := getTFList(mirrorURL, listAll) // get list of versions
+		tflist, errTFList := getTFList(mirrorURL, listAll) // get list of versions
+		if errTFList != nil {
+			return "", fmt.Errorf("Error getting list of versions from %q: %v", mirrorURL, errTFList)
+		}
+
 		version = fmt.Sprintf("~> %v", version)
 		semv, err := SemVerParser(&version, tflist)
 		if err != nil {
@@ -114,7 +124,7 @@ func getTFURLBody(mirrorURL string) (string, error) {
 		// if it does not have slash - append slash
 		mirrorURL = fmt.Sprintf("%s/", mirrorURL)
 	}
-	resp, errURL := http.Get(mirrorURL)
+	resp, errURL := http.Get(mirrorURL) // nolint:gosec // `mirrorURL' is expected to be variable
 	if errURL != nil {
 		logger.Fatalf("Error getting url: %v", errURL)
 	}
@@ -160,10 +170,8 @@ func removeDuplicateVersions(elements []string) []string {
 	result := []string{}
 
 	for _, val := range elements {
-		versionOnly := strings.Trim(val, " *recent")
-		if encountered[versionOnly] {
-			// Do not add duplicate.
-		} else {
+		versionOnly := strings.TrimSuffix(val, " *recent")
+		if !encountered[versionOnly] {
 			// Record this element as an encountered element.
 			encountered[versionOnly] = true
 			// Append to result slice.
@@ -203,14 +211,22 @@ func validMinorVersionFormat(version string) bool {
 
 // ShowLatestVersion show install latest stable tf version
 func ShowLatestVersion(mirrorURL string) {
-	tfversion, _ := getTFLatest(mirrorURL)
+	tfversion, err := getTFLatest(mirrorURL)
+	if err != nil {
+		logger.Fatalf("Error getting latest version from %q: %v", mirrorURL, err)
+	}
+
 	fmt.Printf("%s\n", tfversion)
 }
 
 // ShowLatestImplicitVersion show latest - argument (version) must be provided
 func ShowLatestImplicitVersion(requestedVersion, mirrorURL string, preRelease bool) {
 	if validMinorVersionFormat(requestedVersion) {
-		tfversion, _ := getTFLatestImplicit(mirrorURL, preRelease, requestedVersion)
+		tfversion, err := getTFLatestImplicit(mirrorURL, preRelease, requestedVersion)
+		if err != nil {
+			logger.Fatalf("Error getting latest implicit version %q from %q: %v", requestedVersion, mirrorURL, err)
+		}
+
 		if len(tfversion) > 0 {
 			fmt.Printf("%s\n", tfversion)
 		} else {
diff --git a/lib/lockfile.go b/lib/lockfile.go
--- a/lib/lockfile.go
+++ b/lib/lockfile.go
@@ -21,7 +21,7 @@ func acquireLock(lockFile string, lockWaitMaxAttempts int, lockWaitInterval time
 		if lockFileInfo, err := os.Stat(lockFile); err == nil {
 			logger.Debugf("Lock %q last modification time: %s", lockFile, lockFileInfo.ModTime())
 		} else {
-			logger.Warnf("Unable to get lock %q last modification time: %w", lockFile, err)
+			logger.Warnf("Unable to get lock %q last modification time: %v", lockFile, err)
 		}
 
 		if lockAttempt < lockWaitMaxAttempts {
@@ -45,7 +45,7 @@ func releaseLock(lockFile string, lockedFH *os.File) {
 	}
 
 	if err := lockedFH.Close(); err != nil {
-		logger.Warnf("Failed to release lock %q: %w", lockFile, err)
+		logger.Warnf("Failed to release lock %q: %v", lockFile, err)
 	} else {
 		logger.Debugf("Released lock %q", lockFile)
 	}
@@ -54,7 +54,7 @@ func releaseLock(lockFile string, lockedFH *os.File) {
 
 	if CheckFileExist(lockFile) {
 		if err := os.Remove(lockFile); err != nil {
-			logger.Warnf("Failed to remove lock %q: %w", lockFile, err)
+			logger.Warnf("Failed to remove lock %q: %v", lockFile, err)
 		} else {
 			logger.Debugf("Removed lock %q", lockFile)
 		}
diff --git a/lib/logging.go b/lib/logging.go
--- a/lib/logging.go
+++ b/lib/logging.go
@@ -46,19 +46,15 @@ func InitLogger(logLevel string) *slog.Logger {
 	case "ERROR":
 		h = NewStderrConsoleHandler(ErrorLogging)
 		formatter.SetTemplate(loggingTemplateDebug)
-		break
 	case "TRACE":
 		h = NewStderrConsoleHandler(TraceLogging)
 		formatter.SetTemplate(loggingTemplateDebug)
-		break
 	case "DEBUG":
 		h = NewStderrConsoleHandler(DebugLogging)
 		formatter.SetTemplate(loggingTemplateDebug)
-		break
 	case "NOTICE":
 		h = NewStderrConsoleHandler(NoticeLogging)
 		formatter.SetTemplate(loggingTemplate)
-		break
 	default:
 		h = NewStderrConsoleHandler(NormalLogging)
 		formatter.SetTemplate(loggingTemplate)
diff --git a/lib/param_parsing/environment.go b/lib/param_parsing/environment.go
--- a/lib/param_parsing/environment.go
+++ b/lib/param_parsing/environment.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/parameters.go b/lib/param_parsing/parameters.go
--- a/lib/param_parsing/parameters.go
+++ b/lib/param_parsing/parameters.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -62,6 +63,7 @@ func GetParameters() Params {
 	return params
 }
 
+//nolint:gocyclo
 func populateParams(params Params) Params {
 	var productIds []string
 	var defaultMirrors []string
diff --git a/lib/param_parsing/terraform_version.go b/lib/param_parsing/terraform_version.go
--- a/lib/param_parsing/terraform_version.go
+++ b/lib/param_parsing/terraform_version.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/terragrunt.go b/lib/param_parsing/terragrunt.go
--- a/lib/param_parsing/terragrunt.go
+++ b/lib/param_parsing/terragrunt.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -25,7 +26,12 @@ func GetVersionFromTerragrunt(params Params) (Params, error) {
 			return params, fmt.Errorf("unable to parse HCL file %q", filePath)
 		}
 		var versionFromTerragrunt terragruntVersionConstraints
-		_ = gohcl.DecodeBody(hclFile.Body, nil, &versionFromTerragrunt)
+		diagnostics = gohcl.DecodeBody(hclFile.Body, nil, &versionFromTerragrunt)
+		// do not fail on failure to decode the body, as it may f.e. miss a required block,
+		// though we don't want to fail execution because of that
+		if diagnostics.HasErrors() {
+			logger.Errorf(diagnostics.Error())
+		}
 		if versionFromTerragrunt.TerraformVersionConstraint == "" {
 			logger.Infof("No terraform version constraint in %q", filePath)
 			return params, nil
diff --git a/lib/param_parsing/tfswitch.go b/lib/param_parsing/tfswitch.go
--- a/lib/param_parsing/tfswitch.go
+++ b/lib/param_parsing/tfswitch.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/toml.go b/lib/param_parsing/toml.go
--- a/lib/param_parsing/toml.go
+++ b/lib/param_parsing/toml.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/versiontf.go b/lib/param_parsing/versiontf.go
--- a/lib/param_parsing/versiontf.go
+++ b/lib/param_parsing/versiontf.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -33,7 +34,7 @@ func GetVersionFromVersionsTF(params Params) (Params, error) {
 	}
 
 	logger.Infof("Reading version from Terraform module at %q", relPath)
-	module, _ := tfconfig.LoadModule(params.ChDirPath)
+	module, _ := tfconfig.LoadModule(params.ChDirPath) // nolint:errcheck // covered by conditional below
 	if module.Diagnostics.HasErrors() {
 		logger.Fatalf("Could not load Terraform module at %q", params.ChDirPath)
 	}
diff --git a/lib/product.go b/lib/product.go
--- a/lib/product.go
+++ b/lib/product.go
@@ -5,8 +5,11 @@ import (
 	"strings"
 )
 
+// nolint:revive // FIXME: var-naming: const legacyProductId should be legacyProductID (revive)
 const legacyProductId = "terraform"
 
+// nolint:revive // FIXME: var-naming: struct field PublicKeyId should be PublicKeyID (revive)
+// nolint:revive // FIXME: var-naming: struct field PublicKeyUrl should be PublicKeyURL (revive)
 type ProductDetails struct {
 	ID                    string
 	Name                  string
@@ -26,6 +29,11 @@ type OpenTofuProduct struct {
 	ProductDetails
 }
 
+// nolint:revive // FIXME: var-naming: method GetId should be GetID (revive)
+// nolint:revive // FIXME: var-naming: method GetDefaultMirrorUrl should be GetDefaultMirrorURL (revive)
+// nolint:revive // FIXME: var-naming: method GetArtifactUrl should be GetArtifactURL (revive)
+// nolint:revive // FIXME: var-naming: method GetPublicKeyId should be GetPublicKeyID (revive)
+// nolint:revive // FIXME: var-naming: method GetPublicKeyUrl should be GetPublicKeyURL (revive)
 type Product interface {
 	GetId() string
 	GetName() string
@@ -42,78 +50,111 @@ type Product interface {
 }
 
 // Terraform Product
+// nolint:revive // FIXME: var-naming: method GetId should be GetID (revive)
 func (p TerraformProduct) GetId() string {
 	return p.ID
 }
+
 func (p TerraformProduct) GetName() string {
 	return p.Name
 }
+
+// nolint:revive // FIXME: var-naming: method GetDefaultMirrorUrl should be GetDefaultMirrorURL (revive)
 func (p TerraformProduct) GetDefaultMirrorUrl() string {
 	return p.DefaultMirror
 }
+
 func (p TerraformProduct) GetVersionPrefix() string {
 	return p.VersionPrefix
 }
+
 func (p TerraformProduct) GetExecutableName() string {
 	return p.ExecutableName
 }
+
 func (p TerraformProduct) GetArchivePrefix() string {
 	return p.ArchivePrefix
 }
+
+// nolint:revive // FIXME: var-naming: method GetArtifactUrl should be GetArtifactURL (revive)
 func (p TerraformProduct) GetArtifactUrl(mirrorURL string, version string) string {
 	mirrorURL = strings.TrimRight(mirrorURL, "/")
 	return fmt.Sprintf("%s/%s", mirrorURL, version)
 }
+
+// nolint:revive // FIXME: var-naming: method GetPublicKeyId should be GetPublicKeyID (revive)
 func (p TerraformProduct) GetPublicKeyId() string {
 	return p.PublicKeyId
 }
+
+// nolint:revive // FIXME: var-naming: method GetPublicKeyUrl should be GetPublicKeyURL (revive)
 func (p TerraformProduct) GetPublicKeyUrl() string {
 	return p.PublicKeyUrl
 }
+
 func (p TerraformProduct) GetShaSignatureSuffix() string {
 	return p.GetPublicKeyId() + ".sig"
 }
+
 func (p TerraformProduct) GetRecentVersionProduct(recentFile *RecentFile) []string {
 	return recentFile.Terraform
 }
+
 func (p TerraformProduct) SetRecentVersionProduct(recentFile *RecentFile, versions []string) {
 	recentFile.Terraform = versions
 }
 
 // OpenTofu methods
+// nolint:revive // FIXME: var-naming: method GetId should be GetID (revive)
 func (p OpenTofuProduct) GetId() string {
 	return p.ID
 }
+
 func (p OpenTofuProduct) GetName() string {
 	return p.Name
 }
+
+// nolint:revive // FIXME: var-naming: method GetDefaultMirrorUrl should be GetDefaultMirrorURL (revive)
 func (p OpenTofuProduct) GetDefaultMirrorUrl() string {
 	return p.DefaultMirror
 }
+
 func (p OpenTofuProduct) GetVersionPrefix() string {
 	return p.VersionPrefix
 }
+
 func (p OpenTofuProduct) GetExecutableName() string {
 	return p.ExecutableName
 }
+
 func (p OpenTofuProduct) GetArchivePrefix() string {
 	return p.ArchivePrefix
 }
+
+// nolint:revive // FIXME: parameter 'mirrorURL' is not used (custom Mirror URL is not implemented for OpenTofu? 10-Mar-2025)
+// nolint:revive // FIXME: var-naming: method GetArtifactUrl should be GetArtifactURL (revive)
 func (p OpenTofuProduct) GetArtifactUrl(mirrorURL string, version string) string {
 	return fmt.Sprintf("%s/v%s", p.DefaultDownloadMirror, version)
 }
+
+// nolint:revive // FIXME: var-naming: method GetPublicKeyId should be GetPublicKeyID (revive)
 func (p OpenTofuProduct) GetPublicKeyId() string {
 	return p.PublicKeyId
 }
+
+// nolint:revive // FIXME: var-naming: method GetPublicKeyUrl should be GetPublicKeyURL (revive)
 func (p OpenTofuProduct) GetPublicKeyUrl() string {
 	return p.PublicKeyUrl
 }
+
 func (p OpenTofuProduct) GetShaSignatureSuffix() string {
 	return "gpgsig"
 }
+
 func (p OpenTofuProduct) GetRecentVersionProduct(recentFile *RecentFile) []string {
 	return recentFile.OpenTofu
 }
+
 func (p OpenTofuProduct) SetRecentVersionProduct(recentFile *RecentFile, versions []string) {
 	recentFile.OpenTofu = versions
 }
@@ -147,6 +188,7 @@ var products = []Product{
 	},
 }
 
+// nolint:revive // FIXME: var-naming: func GetProductById should be GetProductByID (revive)
 func GetProductById(id string) Product {
 	for _, product := range products {
 		if strings.EqualFold(product.GetId(), id) {
diff --git a/lib/recent.go b/lib/recent.go
--- a/lib/recent.go
+++ b/lib/recent.go
@@ -89,7 +89,7 @@ func saveRecentFile(data RecentFile, path string) {
 	if err != nil {
 		logger.Errorf("Could not marshal data to JSON: %v", err)
 	}
-	err = os.WriteFile(path, bytes, 0644)
+	err = os.WriteFile(path, bytes, 0o600)
 	if err != nil {
 		logger.Errorf("Could not save file %q: %v", path, err)
 	}
diff --git a/lib/semver.go b/lib/semver.go
--- a/lib/semver.go
+++ b/lib/semver.go
@@ -10,7 +10,10 @@ import (
 // GetSemver : returns version that will be installed based on server constraint provided
 func GetSemver(tfconstraint string, mirrorURL string) (string, error) {
 	listAll := true
-	tflist, _ := getTFList(mirrorURL, listAll) // get list of versions
+	tflist, errTFList := getTFList(mirrorURL, listAll) // get list of versions
+	if errTFList != nil {
+		return "", fmt.Errorf("Error getting list of versions from %q: %v", mirrorURL, errTFList)
+	}
 	logger.Infof("Reading required version from constraint: %q", tfconstraint)
 	tfversion, err := SemVerParser(&tfconstraint, tflist)
 	return tfversion, err
@@ -41,9 +44,8 @@ func SemVerParser(tfconstraint *string, tflist []string) (string, error) {
 			if validVersionFormat(tfversion) { // check if version format is correct
 				logger.Infof("Matched version: %q", tfversion)
 				return tfversion, nil
-			} else {
-				PrintInvalidTFVersion()
 			}
+			PrintInvalidTFVersion()
 		}
 	}
 
diff --git a/lib/symlink.go b/lib/symlink.go
--- a/lib/symlink.go
+++ b/lib/symlink.go
@@ -13,7 +13,7 @@ import (
 func CreateSymlink(cwd string, dir string) error {
 	// If we are on windows the symlink is not working correctly.
 	// Copy the desired terraform binary to the path environment.
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == windows {
 		r, err := os.Open(cwd)
 		if err != nil {
 			return fmt.Errorf("Unable to open source binary: %q", cwd)
@@ -56,19 +56,18 @@ func RemoveSymlink(symlinkPath string) error {
 		If error persist, you may not have the permission to create a symlink at %q.
 		Error: %v
 		`, symlinkPath, symlinkPath, err)
-	} else {
-		errRemove := os.Remove(symlinkPath)
+	}
 
-		if errRemove != nil {
-			return fmt.Errorf(`
-			Unable to remove symlink.
-			Maybe symlink already exist. Try removing existing symlink manually.
-			Try running "unlink %q" to remove existing symlink.
-			If error persist, you may not have the permission to create a symlink at %q.
-			Error: %v
-			`, symlinkPath, symlinkPath, errRemove)
-		}
+	if errRemove := os.Remove(symlinkPath); errRemove != nil {
+		return fmt.Errorf(`
+		Unable to remove symlink.
+		Maybe symlink already exist. Try removing existing symlink manually.
+		Try running "unlink %q" to remove existing symlink.
+		If error persist, you may not have the permission to create a symlink at %q.
+		Error: %v
+		`, symlinkPath, symlinkPath, errRemove)
 	}
+
 	return nil
 }
 
@@ -98,6 +97,8 @@ func ChangeSymlink(binVersionPath string, binPath string) {
 }
 
 // ChangeProductSymlink : move symlink for product to existing binary
+//
+//nolint:gocyclo
 func ChangeProductSymlink(product Product, binVersionPath string, userBinPath string) error {
 	homedir := GetHomeDirectory() // get user's home directory
 	homeBinPath := filepath.Join(homedir, "bin", product.GetExecutableName())
@@ -155,9 +156,12 @@ func ChangeProductSymlink(product Product, binVersionPath string, userBinPath st
 		}
 		logger.Noticef("Installation location: %q", location.path)
 
-		/* remove current symlink if exist*/
+		/* remove current symlink if exist */
 		if CheckSymlink(location.path) {
-			_ = RemoveSymlink(location.path)
+			logger.Debugf("Clearing away symlink before re-creating it: %q", location.path)
+			if err := RemoveSymlink(location.path); err != nil {
+				return fmt.Errorf("Error removing symlink %q: %v", location.path, err)
+			}
 		}
 
 		/* set symlink to desired version */
@@ -167,8 +171,8 @@ func ChangeProductSymlink(product Product, binVersionPath string, userBinPath st
 
 			// Print helper message to export PATH if the directory is not in PATH only for non-Windows systems,
 			// as it's all complicated on Windows. See https://github.com/warrensbox/terraform-switcher/issues/558
-			if runtime.GOOS != "windows" {
-				var isDirInPath bool = false
+			if runtime.GOOS != windows {
+				isDirInPath := false
 
 				for _, envPathElement := range strings.Split(os.Getenv("PATH"), ":") {
 					expandedEnvPathElement := strings.TrimRight(strings.Replace(envPathElement, "~", homedir, 1), "/")
diff --git a/main.go b/main.go
--- a/main.go
+++ b/main.go
@@ -20,7 +20,7 @@ var (
 )
 
 func main() {
-	var err error = nil
+	var err error
 	switch {
 	case parameters.VersionFlag:
 		fmt.Printf("Version: ")
diff --git a/www/docs/Continuous-Integration.md b/www/docs/Continuous-Integration.md
--- a/www/docs/Continuous-Integration.md
+++ b/www/docs/Continuous-Integration.md
@@ -1,8 +1,11 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Jenkins setup
+
 ![jenkins_tfswitch](static/jenkins_tfswitch.png)
 
 ```sh
-#!/bin/bash 
+#!/bin/bash
 
 echo "Installing tfswitch locally"
 wget https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/install.sh  #Get the installer on to your machine
@@ -17,8 +20,8 @@ export PATH=$PATH:$CUSTOMBIN    #Add custom bin path to PATH environment
 
 $CUSTOMBIN/tfswitch -b $CUSTOMBIN/terraform 0.11.7 #or simply tfswitch -b $CUSTOMBIN/terraform 0.11.7
 
-#OR 
-$CUSTOMBIN/tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform  #or simply tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform 
+#OR
+$CUSTOMBIN/tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform  #or simply tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform
 
 terraform -v                    #testing version
 ```
@@ -27,7 +30,8 @@ terraform -v                    #testing version
 
 ![cirecleci_tfswitch](static/circleci_tfswitch.png)
 
-Example config yaml
+Example config YAML
+
 ```yaml
 version: 2
 jobs:
@@ -39,8 +43,8 @@ jobs:
 
     steps:
       - checkout
-      - run: 
-          command: |    
+      - run:
+          command: |
             set +e   
             apt-get update 
             apt-get install -y wget 
@@ -59,7 +63,7 @@ jobs:
             export PATH=$PATH:$CUSTOMBIN    #Add custom bin path to PATH environment
 
             $CUSTOMBIN/tfswitch -b $CUSTOMBIN/terraform 0.11.7 #or simply tfswitch -b $CUSTOMBIN/terraform 0.11.7
-            
+
             #OR 
             $CUSTOMBIN/tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform  #or simply tfswitch -d 0.11.7 -b $CUSTOMBIN/terraform 
 
diff --git a/www/docs/How-to-Contribute.md b/www/docs/How-to-Contribute.md
--- a/www/docs/How-to-Contribute.md
+++ b/www/docs/How-to-Contribute.md
@@ -1,66 +1,88 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Step-by-step instructions
 
-An open source project becomes meaningful when people collaborate to improve the code. 
+An open source project becomes meaningful when people collaborate to improve the code.
 
 Feel free to look at the code, critique and make suggestions. Let's make `tfswitch` better!
 
 ## Required version
+
 ```sh
 go version 1.23
 ```
 
 ### Step 1 - Create workspace
-*Skip this step if you already have a GitHub go workspace*   
+
+_Skip this step if you already have a GitHub go workspace_  
 Create a GitHub workspace.
 
 ![GitHub Workspace](static/contribute/tfswitch-workspace.gif "Create GitHub Workspace")
 
 ### Step 2 - Set GOPATH
-*Skip this step if you already have a GitHub go workspace*    
-Export your GOPATH environment variable in your `go` directory.   
+
+_Skip this step if you already have a GitHub go workspace_  
+Export your GOPATH environment variable in your `go` directory.
+
 ```sh
 export GOPATH=`pwd`
 ```
+
 ![gopath](static/contribute/tfswitch-gopath.gif "gopath")
 
 ### Step 3 - Clone repository
-Git clone this repository.  
-```sh 
+
+Git clone this repository.
+
+```sh
 git clone git@github.com:warrensbox/terraform-switcher.git
 ```
+
 ![gitclone](static/contribute/tfswitch-git-clone.gif "Git Clone")
 
 ### Step 4 - Get dependencies
-Go get all the dependencies.   
 
-```sh 
+Go get all the dependencies.
+
+```sh
 go mod download
 ```
-```sh 
+
+```sh
 go get -v -t -d ./...
 ```
+
 Test the code (optional).
-```sh  
+
+```sh
 go vet -tests=false ./...
 ```
-```sh 
+
+```sh
 go test -v ./...
 ```
+
 ![go get](static/contribute/tfswitch-go-get.gif)
 
 ### Step 5 - Build executable
-Create a new branch.   
-```sh 
+
+Create a new branch.
+
+```sh
 git checkout -b feature/put-your-branch-name-here
 ```
+
 Refactor and add new features to the code.  
-Go build the code.   
-```sh 
+Go build the code.
+
+```sh
 go build -o test-tfswitch
 ```
+
 Test the code and create a new pull request!
 
 ![go build](static/contribute/tfswitch-build.gif)
 
 ### Contributors
+
 Click <a href="https://github.com/warrensbox/terraform-switcher/graphs/contributors" target="_blank">here</a> to see all contributors.
diff --git a/www/docs/Installation.md b/www/docs/Installation.md
--- a/www/docs/Installation.md
+++ b/www/docs/Installation.md
@@ -1,19 +1,23 @@
 # Installation
+
 `tfswitch` is available for Windows, macOS and Linux based operating systems.
 
 ## Windows
+
 Download and extract the Windows version of `tfswitch` that is compatible with your system.  
 We are building binaries for 386, amd64, arm6 and arm7 CPU structure.  
 See the [release page](https://github.com/warrensbox/terraform-switcher/releases/latest) for your download.
 
 ## Homebrew
-Installation for macOS is the easiest with Homebrew. <a href="https://brew.sh/" target="_blank">If you do not have homebrew installed, click here</a>.
+
+Installation for macOS is the easiest with Homebrew. <a href="https://brew.sh/" target="_blank">If you do not have Homebrew installed, click here</a>.
 
 ```shell
 brew install warrensbox/tap/tfswitch
 ```
 
 ## Linux
+
 Installation for Linux operating systems.
 
 ```sh
@@ -22,17 +26,20 @@ curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/i
 
 By default installer script will try to download `tfswitch` binary into `/usr/local/bin`  
 To install at custom path use below:
+
 ```sh
 curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/install.sh | bash -s -- -b $HOME/.local/bin
 ```
 
 By default installer script will try to download latest version of `tfswitch` binary  
 To install custom (not latest) version use:
+
 ```sh
 curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/install.sh | bash -s -- 1.1.1
 ```
 
 Both options can be combined though:
+
 ```sh
 curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/install.sh | bash -s -- -b $HOME/.local/bin 1.1.1
 ```
@@ -52,5 +59,3 @@ yay tfswitch-bin
 Alternatively, you can install the binary from the source <a href="https://github.com/warrensbox/terraform-switcher/releases" target="_blank">here</a>.
 
 [Having trouble installing](https://tfswitch.warrensbox.com/Troubleshoot/).
-
-
diff --git a/www/docs/Troubleshoot.md b/www/docs/Troubleshoot.md
--- a/www/docs/Troubleshoot.md
+++ b/www/docs/Troubleshoot.md
@@ -1,5 +1,7 @@
+<!-- markdownlint-disable MD041 -->
 
 Problem:
+
 ```sh
 install: can't change permissions of /usr/local/bin: Operation not permitted
 ```
@@ -16,7 +18,7 @@ install: can't change permissions of /usr/local/bin: Operation not permitted
 install: cannot create regular file '/usr/local/bin/tfswitch': Permission denied
 ```
 
-Solution: You probably need to have privileges to install *tfswitch* at /usr/local/bin.
+Solution: You probably need to have privileges to install _tfswitch_ at /usr/local/bin.
 
 Try the following:
 
@@ -34,9 +36,9 @@ export PATH=$PATH:$HOME/.bin #Export your .bin into your path
 #You should probably add step 4 in your `.bash_profile` in your $HOME directory.
 
 #Next, try:
-`tfswitch -b $HOME/.bin/terraform 0.11.7` 
+`tfswitch -b $HOME/.bin/terraform 0.11.7`
 
-#or simply 
+#or simply
 
 `tfswitch -b $HOME/.bin/terraform`
 
diff --git a/www/docs/Upgrade-or-Uninstall.md b/www/docs/Upgrade-or-Uninstall.md
--- a/www/docs/Upgrade-or-Uninstall.md
+++ b/www/docs/Upgrade-or-Uninstall.md
@@ -1,10 +1,13 @@
-## Upgrade:
+<!-- markdownlint-disable MD041 MD024 -->
+
+## Upgrade
 
 ### Homebrew
 
 ```shell
 brew upgrade warrensbox/tap/tfswitch
 ```
+
 ### Linux
 
 Rerun:
@@ -13,17 +16,18 @@ Rerun:
 curl -L https://raw.githubusercontent.com/warrensbox/terraform-switcher/master/install.sh | bash
 ```
 
-## Uninstall:
+## Uninstall
 
 ### Homebrew
 
 ```shell
 brew uninstall warrensbox/tap/tfswitch
 ```
+
 ### Linux
 
 Run (replace `/usr/local/bin` if you installed `tfswitch` to a custom location):
 
 ```sh
 rm /usr/local/bin/tfswitch
-```
\ No newline at end of file
+```
diff --git a/www/docs/index.md b/www/docs/index.md
--- a/www/docs/index.md
+++ b/www/docs/index.md
@@ -2,9 +2,7 @@
 
 ![Logo](static/logo.png)
 
-
-The `tfswitch` command line tool lets you switch between different versions of <a href="https://www.terraform.io/" target="_blank">terraform</a>.
+The `tfswitch` command-line tool lets you switch between different versions of <a href="https://www.terraform.io/" target="_blank">terraform</a>.
 If you do not have a particular version of terraform installed, `tfswitch` lets you download the version you desire.
-The installation is minimal and easy. 
-Once installed, simply select the version you require from the dropdown and start using terraform. 
-
+The installation is minimal and easy.
+Once installed, simply select the version you require from the dropdown and start using terraform.
diff --git a/www/docs/usage/ci-cd.md b/www/docs/usage/ci-cd.md
--- a/www/docs/usage/ci-cd.md
+++ b/www/docs/usage/ci-cd.md
@@ -1,8 +1,10 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Set a default TF version for CI/CD pipeline
 
 1. When using a CI/CD pipeline, you may want a default or fallback version to avoid the pipeline from hanging.
 2. Ex: `tfswitch -d 1.2.3` or `tfswitch --default 1.2.3` installs version `1.2.3` when no other versions could be detected.
-[Also, see CICD example](../Continuous-Integration.md)
+   [Also, see CICD example](../Continuous-Integration.md)
 
 ## Automatically switch with bash
 
@@ -20,7 +22,7 @@ cdtfswitch(){
 alias cd='cdtfswitch'
 ```
 
-## Automatically switch with zsh
+## Automatically switch with Zsh
 
 Add the following to the end of your `~/.zshrc` file:
 
@@ -37,11 +39,12 @@ load-tfswitch
 ```
 
 > NOTE: if you see an error like this: `command not found: add-zsh-hook`, then you might be on an older version of zsh (see below), or you simply need to load `add-zsh-hook` by adding this to your `.zshrc`:
->    ```
->    autoload -U add-zsh-hook
->    ```
+>
+> ```sh
+> autoload -U add-zsh-hook
+> ```
 
-### Older version of zsh
+### Older version of Zsh
 
 ```sh
 cd(){
@@ -67,7 +70,7 @@ function switch_terraform --on-event fish_postexec
 
         grep -c "required_version" *.tf > /dev/null
         set --local tf_contains_version $status
-        
+
         if test $tf_contains_version -eq 0
             command tfswitch
         end
diff --git a/www/docs/usage/commandline.md b/www/docs/usage/commandline.md
--- a/www/docs/usage/commandline.md
+++ b/www/docs/usage/commandline.md
@@ -1,13 +1,17 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Use dropdown menu to select version
+
 ![tfswitch](../static/tfswitch.gif "tfswitch")
 
-1.  You can switch between different versions of terraform by typing the command `tfswitch` on your terminal.
-2.  Select the version of terraform you require by using the up and down arrow.
-3.  Hit **Enter** to select the desired version.
+1. You can switch between different versions of terraform by typing the command `tfswitch` on your terminal.
+2. Select the version of terraform you require by using the up and down arrow.
+3. Hit **Enter** to select the desired version.
 
 The most recently selected versions are presented at the top of the dropdown.
 
 ## Supply version on command line
+
 <img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-v4.gif" alt="drawing" style="width: 600px;"/>
 
 1. You can also supply the desired version as an argument on the command line.
@@ -15,6 +19,7 @@ The most recently selected versions are presented at the top of the dropdown.
 3. Hit **Enter** to switch.
 
 ## See all versions including beta, alpha and release candidates(rc)
+
 <img src="https://s3.us-east-2.amazonaws.com/kepler-images/warrensbox/tfswitch/tfswitch-v5.gif" alt="drawing" style="width: 600px;"/>
 
 1. Display all versions including beta, alpha and release candidates(rc).
@@ -53,8 +58,8 @@ tfswitch # Will automatically switch to terraform version 0.14.4
 
 This can either be set to:
 
- * `terraform`
- * `opentofu`
+- `terraform`
+- `opentofu`
 
 For example:
 
@@ -68,11 +73,11 @@ tfswitch # Will install opentofu instead of terraform
 `TF_LOG_LEVEL` environment variable can be set to override default log level.
 
 - Supported log levels:
-  - `ERROR`:  includes `PANIC`, `FATAL`, `ERROR`
-  - `INFO`:   includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `INFO` (default)
+  - `ERROR`: includes `PANIC`, `FATAL`, `ERROR`
+  - `INFO`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `INFO` (default)
   - `NOTICE`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`
-  - `DEBUG`:  includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`
-  - `TRACE`:  includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`, `TRACE`
+  - `DEBUG`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`
+  - `TRACE`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`, `TRACE`
   - Any other log level value falls under default logging level
 
 For example:
@@ -102,7 +107,7 @@ tfswitch # Will install binary for amd64 architecture
 ### `TF_BINARY_PATH`
 
 `tfswitch` defaults to install to the `/usr/local/bin/` directory (and falls back to `$HOME/bin/` otherwise). The target filename is resolved automatically based on the `product` parameter.  
-`TF_BINARY_PATH` environment variable can be set to specify a **full installation path** (directory + file name). If target directory does not exist, `tfswitch` falls back to `$HOME/bin/` directory.
+`TF_BINARY_PATH` environment variable can be set to specify a **full installation path** (directory + filename). If target directory does not exist, `tfswitch` falls back to `$HOME/bin/` directory.
 
 For example:
 
@@ -137,7 +142,7 @@ tfswitch # Will download actual binary to /var/cache/.terraform.versions/
 
 ## Install latest implicit version for beta, alpha and release candidates(rc)
 
-1. Install the latest implicit pre-release version.
+1. Install the latest implicit prerelease version.
 2. Ex: `tfswitch -p 0.13` or `tfswitch --latest-pre 0.13` downloads 0.13.0-rc1 (latest) version.
 3. Hit **Enter** to install.
 
@@ -155,13 +160,13 @@ tfswitch # Will download actual binary to /var/cache/.terraform.versions/
 
 ## Show latest implicit version for beta, alpha and release candidates(rc)
 
-1. Show the latest implicit pre-release version.
+1. Show the latest implicit prerelease version.
 2. Ex: `tfswitch -P 0.13` or `tfswitch --show-latest-pre 0.13` shows 0.13.0-rc1 (latest) version.
 3. Hit **Enter** to show.
 
 ## Use custom mirror
 
-To install from a remote mirror other than the default(https://releases.hashicorp.com/terraform). Use the `-m` or `--mirror` parameter.
+To install from a remote mirror other than the default (<https://releases.hashicorp.com/terraform>). Use the `-m` or `--mirror` parameter.
 
 ```bash
 tfswitch --mirror https://example.jfrog.io/artifactory/hashicorp`
diff --git a/www/docs/usage/config-files.md b/www/docs/usage/config-files.md
--- a/www/docs/usage/config-files.md
+++ b/www/docs/usage/config-files.md
@@ -1,3 +1,5 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Get the version from a subdirectory
 
 While using the file configuration it might be necessary to change the working directory. You can do that with the `--chdir` or `-c` parameter.
@@ -11,7 +13,7 @@ tfswitch -c terraform_dir
 
 If a `.tf` file with the version constraints is included in the current directory, `tfswitch` should automatically download or switch to that terraform version.  
 Also please refer to [Order of Terraform version definition precedence](general.md) page for more information on how `tfswitch` determines the version to use.  
-For example, the following should automatically switch to the latest available version newer than `0.12.8`:  
+For example, the following should automatically switch to the latest available version newer than `0.12.8`:
 
 ```hcl
 terraform {
@@ -34,11 +36,11 @@ terraform {
 2. For example, `echo "0.10.5" >> .tfswitchrc` for version `0.10.5`
 3. Run the command `tfswitch` in the same directory as this `.tfswitchrc` file
 
-*Instead of a `.tfswitchrc` file, a `.terraform-version` file may be used for compatibility with [`tfenv`](https://github.com/tfutils/tfenv#terraform-version-file) and other tools which use it*
+_Instead of a `.tfswitchrc` file, a `.terraform-version` file may be used for compatibility with [`tfenv`](https://github.com/tfutils/tfenv#terraform-version-file) and other tools which use it_
 
-## Use `.tfswitch.toml` file  (For non-admin users with limited privilege on their computers)
+## Use `.tfswitch.toml` file (For non-admin users with limited privilege on their computers)
 
-`tfswitch` defaults to install to the `/usr/local/bin/` directory (and falls back to `$HOME/bin/` otherwise). The target filename is resolved automatically based on the `product` attribute ([see below](#setting-product-using-tfswitchtoml-file)). If you do not have write access to `/usr/local/bin/` directory, you can use the `.tfswitch.toml` file to specify a **full installation path** (directory + file name).  
+`tfswitch` defaults to install to the `/usr/local/bin/` directory (and falls back to `$HOME/bin/` otherwise). The target filename is resolved automatically based on the `product` attribute ([see below](#setting-product-using-tfswitchtoml-file)). If you do not have write access to `/usr/local/bin/` directory, you can use the `.tfswitch.toml` file to specify a **full installation path** (directory + filename).  
 This is similar to using a `.tfswitchrc` file, but you specify a custom binary path for the installation:
 
 ![toml1](../static/tfswitch-v7.gif)
@@ -98,11 +100,11 @@ log-level = "INFO"
 ```
 
 - Supported log levels:
-  - `ERROR`:  includes `PANIC`, `FATAL`, `ERROR`
-  - `INFO`:   includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `INFO` (default)
+  - `ERROR`: includes `PANIC`, `FATAL`, `ERROR`
+  - `INFO`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `INFO` (default)
   - `NOTICE`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`
-  - `DEBUG`:  includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`
-  - `TRACE`:  includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`, `TRACE`
+  - `DEBUG`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`
+  - `TRACE`: includes `PANIC`, `FATAL`, `ERROR`, `WARN`, `NOTICE`, `INFO`, `DEBUG`, `TRACE`
   - Any other log level value falls under default logging level
 
 ## Overriding CPU architecture type for the downloaded binary using `.tfswitch.toml` file
@@ -130,6 +132,7 @@ install = "/var/cache"
 ```
 
 **NOTE**:
+
 - Current user must have write permissions to the target directory
 - If the target directory does not exist, `tfswitch` will create it
 
diff --git a/www/docs/usage/general.md b/www/docs/usage/general.md
--- a/www/docs/usage/general.md
+++ b/www/docs/usage/general.md
@@ -1,13 +1,15 @@
+<!-- markdownlint-disable MD041 -->
+
 ## Order of Terraform version definition precedence
 
-| Order | Method |
-| --- | ----------- |
-| 1 | `$HOME/.tfswitch.toml` (`version` parameter) |
-| 2 | `.tfswitchrc` (version as a string) |
-| 3 | `.terraform-version` (version as a string) |
-| 4 | Terraform root module (`required_version` constraint) |
-| 5 | `terragrunt.hcl` (`terraform_version_constraint` parameter) |
-| 6 | Environment variable (`TF_VERSION`) |
+| Order | Method                                                      |
+| ----- | ----------------------------------------------------------- |
+| 1     | `$HOME/.tfswitch.toml` (`version` parameter)                |
+| 2     | `.tfswitchrc` (version as a string)                         |
+| 3     | `.terraform-version` (version as a string)                  |
+| 4     | Terraform root module (`required_version` constraint)       |
+| 5     | `terragrunt.hcl` (`terraform_version_constraint` parameter) |
+| 6     | Environment variable (`TF_VERSION`)                         |
 
 With 1 being the **lowest** precedence and 7 — the **highest**  
-*(If you disagree with this order of precedence, please open an issue)*
+_(If you disagree with this order of precedence, please open an issue)_
diff --git a/www/mkdocs.yml b/www/mkdocs.yml
--- a/www/mkdocs.yml
+++ b/www/mkdocs.yml
@@ -16,15 +16,14 @@ nav:
   - Home: index.md
   - Installation: Installation.md
   - Usage:
-    - General: usage/general.md
-    - Command line: usage/commandline.md
-    - Config files: usage/config-files.md
-    - CI/CD: usage/ci-cd.md
+      - General: usage/general.md
+      - Command line: usage/commandline.md
+      - Config files: usage/config-files.md
+      - CI/CD: usage/ci-cd.md
   - CI/CD Examples: Continuous-Integration.md
   - Upgrade-or-Uninstall.md
   - How-to-Contribute.md
   - Troubleshoot.md
-
 # WARNING -  Config value 'google_analytics': The configuration option
 # google_analytics has been deprecated and will be removed in a future release
 # of MkDocs. See the options available on your theme for an alternative.


Test patch:
diff --git a/lib/command_test.go b/lib/command_test.go
--- a/lib/command_test.go
+++ b/lib/command_test.go
@@ -9,7 +9,6 @@ import (
 
 // TestNewCommand : pass value and check if returned value is a pointer
 func TestNewCommand(t *testing.T) {
-
 	testCmd := "terraform"
 	cmd := lib.NewCommand(testCmd)
 
@@ -22,7 +21,6 @@ func TestNewCommand(t *testing.T) {
 
 // TestPathList : check if bin path exist
 func TestPathList(t *testing.T) {
-
 	testCmd := ""
 	cmd := lib.NewCommand(testCmd)
 	listBin := cmd.PathList()
@@ -34,14 +32,9 @@ func TestPathList(t *testing.T) {
 	}
 }
 
-type Command struct {
-	name string
-}
-
 // TestFind : check common "cd" command exist
 // This is assuming that Windows and linux has the "cd" command
 func TestFind(t *testing.T) {
-
 	testCmd := "cd"
 	cmd := lib.NewCommand(testCmd)
 
diff --git a/lib/download_test.go b/lib/download_test.go
--- a/lib/download_test.go
+++ b/lib/download_test.go
@@ -5,7 +5,6 @@ import (
 	"bytes"
 	"crypto/sha256"
 	"encoding/hex"
-	"fmt"
 	"io"
 	"net/http"
 	"net/http/httptest"
@@ -13,13 +12,11 @@ import (
 	"os"
 	"path/filepath"
 	"regexp"
-	"runtime"
 	"strings"
 	"sync"
 	"testing"
 
 	"github.com/ProtonMail/gopenpgp/v2/crypto"
-	"github.com/mitchellh/go-homedir"
 )
 
 // TestDownloadFromURL_FileNameMatch : Check expected filename exist when downloaded
@@ -28,26 +25,21 @@ func TestDownloadFromURL_FileNameMatch(t *testing.T) {
 	hashiURL := "https://releases.hashicorp.com/terraform/"
 	installVersion := "terraform_"
 	tempDir := t.TempDir()
-	installPath := fmt.Sprintf(tempDir + string(os.PathSeparator) + ".terraform.versions_test")
+	installLocation := filepath.Join(tempDir, ".terraform.versions_test")
 	macOS := "_darwin_amd64.zip"
 
-	home, err := homedir.Dir()
-	if err != nil {
-		logger.Fatalf("Could not detect home directory")
-	}
-
-	t.Logf("Current home directory: %q", home)
-	if runtime.GOOS != "windows" {
-		installLocation = filepath.Join(home, installPath)
-	} else {
-		installLocation = installPath
-	}
 	t.Logf("install Location: %v", installLocation)
 
 	// create /.terraform.versions_test/ directory to store code
 	if _, err := os.Stat(installLocation); os.IsNotExist(err) {
 		t.Logf("Creating directory for terraform: %v", installLocation)
-		err = os.MkdirAll(installLocation, 0755)
+		err = os.MkdirAll(installLocation, 0o755)
+
+		t.Cleanup(func() {
+			defer os.Remove(tempDir)
+			t.Logf("Cleanup temporary directory %q", tempDir)
+		})
+
 		if err != nil {
 			t.Logf("Unable to create directory for terraform: %v", installLocation)
 			t.Error("Test fail")
@@ -77,16 +69,11 @@ func TestDownloadFromURL_FileNameMatch(t *testing.T) {
 		t.Error("Download file mismatches expected file (unexpected)")
 	}
 
-	//check file name is what is expected
-	_, err = os.Stat(expectedFile)
-	if err != nil {
+	// check file name is what is expected
+	_, checkErr := os.Stat(expectedFile)
+	if checkErr != nil {
 		t.Logf("Expected file does not exist %v", expectedFile)
 	}
-
-	t.Cleanup(func() {
-		defer os.Remove(tempDir)
-		t.Logf("Cleanup temporary directory %q", tempDir)
-	})
 }
 
 // TestDownloadFromURL_Valid : Test if https://releases.hashicorp.com/terraform/ is still valid
@@ -110,6 +97,7 @@ type DownloadProductTestConfig struct {
 	PublicKey           string
 }
 
+//nolint:gocyclo
 func setupTestDownloadServer(t *testing.T, downloadProductTestConfig *DownloadProductTestConfig) *httptest.Server {
 	logger = InitLogger("DEBUG")
 	gpgKey, err := crypto.GenerateKey("TestProductSign", "example@localhost.com", "RSA", 1024)
@@ -129,7 +117,9 @@ func setupTestDownloadServer(t *testing.T, downloadProductTestConfig *DownloadPr
 		if err != nil {
 			t.Fatal(err)
 		}
-		zipFileContentWriter.Write(executableBytes)
+		if _, err := zipFileContentWriter.Write(executableBytes); err != nil {
+			t.Fatal(err)
+		}
 		zipWriter.Flush()
 		zipWriter.Close()
 		downloadProductTestConfig.ZipFileContent = zipFileBuffer.Bytes()
@@ -181,19 +171,27 @@ func setupTestDownloadServer(t *testing.T, downloadProductTestConfig *DownloadPr
 		case "/testproduct/gpg-key.txt":
 			w.Header().Set("Content-Type", "text/html")
 			w.WriteHeader(http.StatusOK)
-			w.Write([]byte(downloadProductTestConfig.PublicKey))
+			if _, err := w.Write([]byte(downloadProductTestConfig.PublicKey)); err != nil {
+				t.Error(err)
+			}
 		case "/productdownload/2.1.0/my_product_download_2.1.0_linux_amd64.zip":
 			w.Header().Set("Content-Type", "application/zip")
 			w.WriteHeader(http.StatusOK)
-			w.Write(downloadProductTestConfig.ZipFileContent)
+			if _, err := w.Write(downloadProductTestConfig.ZipFileContent); err != nil {
+				t.Error(err)
+			}
 		case "/productdownload/2.1.0/my_product_download_2.1.0_SHA256SUMS":
 			w.Header().Set("Content-Type", "text/plain")
 			w.WriteHeader(http.StatusOK)
-			w.Write([]byte(downloadProductTestConfig.ChecksumFileContent))
+			if _, err := w.Write([]byte(downloadProductTestConfig.ChecksumFileContent)); err != nil {
+				t.Error(err)
+			}
 		case "/productdownload/2.1.0/my_product_download_2.1.0_SHA256SUMS." + downloadProductTestConfig.GpgFingerprint + ".sig":
 			w.Header().Set("Content-Type", "text/plain")
 			w.WriteHeader(http.StatusOK)
-			w.Write(signatureObj.GetBinary())
+			if _, err := w.Write(signatureObj.GetBinary()); err != nil {
+				t.Error(err)
+			}
 		default:
 			http.NotFoundHandler().ServeHTTP(w, r)
 		}
diff --git a/lib/files_test.go b/lib/files_test.go
--- a/lib/files_test.go
+++ b/lib/files_test.go
@@ -4,7 +4,6 @@ import (
 	"bufio"
 	"bytes"
 	"io"
-	"io/ioutil"
 	"os"
 	"path/filepath"
 	"regexp"
@@ -108,12 +107,15 @@ func TestUnzip(t *testing.T) {
 	installPath := "/.terraform.versions_test/"
 	var pathToTestFile string
 	switch runtime.GOOS {
-	case "windows":
+	case windows:
 		pathToTestFile = "../test-data/test-data_windows.zip"
 	default:
 		pathToTestFile = "../test-data/test-data.zip"
 	}
-	absPath, _ := filepath.Abs(pathToTestFile)
+	absPath, err := filepath.Abs(pathToTestFile)
+	if err != nil {
+		t.Error(err)
+	}
 
 	t.Logf("Absolute Path: %q", absPath)
 
@@ -146,8 +148,8 @@ func TestUnzip(t *testing.T) {
 		t.Error(err)
 	}
 	// Ensure terraform file contains test content from
-	if string(terraformFileContent[:]) != "TerraformBinaryContent\n" {
-		t.Errorf("Terraform test file content does not match expected value: %s", string(terraformFileContent[:]))
+	if string(terraformFileContent) != "TerraformBinaryContent\n" {
+		t.Errorf("Terraform test file content does not match expected value: %s", string(terraformFileContent))
 	}
 
 	// Ensure README and LICENSE files don't exist
@@ -168,7 +170,7 @@ func TestUnzip_with_file_to_unzip(t *testing.T) {
 	var pathToTestFile string
 	var expectedFilename string
 	switch runtime.GOOS {
-	case "windows":
+	case windows:
 		pathToTestFile = "../test-data/test-data_windows.zip"
 		expectedFilename = "another_file.exe"
 	default:
@@ -176,7 +178,10 @@ func TestUnzip_with_file_to_unzip(t *testing.T) {
 		expectedFilename = "another_file"
 	}
 
-	absPath, _ := filepath.Abs(pathToTestFile)
+	absPath, err := filepath.Abs(pathToTestFile)
+	if err != nil {
+		t.Error(err)
+	}
 
 	t.Logf("Absolute Path: %q", absPath)
 
@@ -204,13 +209,13 @@ func TestUnzip_with_file_to_unzip(t *testing.T) {
 		t.Errorf("File does not exist %v", expectedExtractFile)
 	}
 
-	expectedFileContent, err := ioutil.ReadFile(expectedExtractFile)
+	expectedFileContent, err := os.ReadFile(expectedExtractFile)
 	if err != nil {
 		t.Error(err)
 	}
 	// Ensure terraform file contains test content from
-	if !strings.Contains(string(expectedFileContent[:]), "This is another executable") {
-		t.Errorf("Extract test file (%q) content does not match expected value: %s", expectedExtractFile, string(expectedFileContent[:]))
+	if !strings.Contains(string(expectedFileContent), "This is another executable") {
+		t.Errorf("Extract test file (%q) content does not match expected value: %s", expectedExtractFile, string(expectedFileContent))
 	}
 
 	// Ensure README and LICENSE files don't exist
@@ -262,7 +267,7 @@ func TestWriteLines(t *testing.T) {
 	installPath := "/.terraform.versions_test/"
 	recentFile := "RECENT"
 	semverRegex := regexp.MustCompile(`\A\d+(\.\d+){2}(-\w+\d*)?\z`)
-	//semverRegex := regexp.MustCompile(`\A\d+(\.\d+){2}\z`)
+	// semverRegex := regexp.MustCompile(`\A\d+(\.\d+){2}\z`)
 
 	homedir, errCurr := homedir.Dir()
 	if errCurr != nil {
@@ -273,9 +278,9 @@ func TestWriteLines(t *testing.T) {
 	createDirIfNotExist(installLocation)
 
 	recentFilePath := filepath.Join(installLocation, recentFile)
-	test_array := []string{"0.1.1", "0.0.2", "0.0.3", "0.12.0-rc1", "0.12.0-beta1"}
+	testArray := []string{"0.1.1", "0.0.2", "0.0.3", "0.12.0-rc1", "0.12.0-beta1"}
 
-	errWrite := WriteLines(test_array, recentFilePath)
+	errWrite := WriteLines(testArray, recentFilePath)
 
 	if errWrite != nil {
 		t.Logf("Write should work %v (unexpected)", errWrite)
@@ -341,7 +346,7 @@ func TestReadLines(t *testing.T) {
 	createDirIfNotExist(installLocation)
 
 	recentFilePath := filepath.Join(installLocation, recentFile)
-	test_array := []string{"0.0.1", "0.0.2", "0.0.3", "0.12.0-rc1", "0.12.0-beta1"}
+	testArray := []string{"0.0.1", "0.0.2", "0.0.3", "0.12.0-rc1", "0.12.0-beta1"}
 
 	var (
 		file      *os.File
@@ -352,7 +357,7 @@ func TestReadLines(t *testing.T) {
 		t.Errorf("Error: %s", errCreate)
 	}
 
-	for _, item := range test_array {
+	for _, item := range testArray {
 		_, err := file.WriteString(strings.TrimSpace(item) + "\n")
 		if err != nil {
 			t.Errorf("Error: %s", err)
@@ -390,17 +395,17 @@ func TestIsDirEmpty(t *testing.T) {
 	}
 	installLocation := filepath.Join(homedir, installPath)
 
-	test_dir := current.Format("2006-01-02")
-	test_dir_path := filepath.Join(installLocation, test_dir)
-	t.Logf("Create test dir: %v \n", test_dir)
+	testDir := current.Format("2006-01-02")
+	testDirPath := filepath.Join(installLocation, testDir)
+	t.Logf("Create test dir: %v \n", testDir)
 
 	createDirIfNotExist(installLocation)
 
-	createDirIfNotExist(test_dir_path)
+	createDirIfNotExist(testDirPath)
 
-	empty := IsDirEmpty(test_dir_path)
+	empty := IsDirEmpty(testDirPath)
 
-	t.Logf("Expected directory to be empty %v [expected]", test_dir_path)
+	t.Logf("Expected directory to be empty %v [expected]", testDirPath)
 
 	if empty == true {
 		t.Logf("Directory empty")
@@ -408,7 +413,7 @@ func TestIsDirEmpty(t *testing.T) {
 		t.Error("Directory not empty")
 	}
 
-	cleanUp(test_dir_path)
+	cleanUp(testDirPath)
 	cleanUp(installLocation)
 }
 
@@ -475,7 +480,6 @@ func TestPath(t *testing.T) {
 
 // TestGetFileName : remove file ext.  .tfswitch.config returns .tfswitch
 func TestGetFileName(t *testing.T) {
-
 	fileNameWithExt := "file.toml"
 
 	fileName := GetFileName(fileNameWithExt)
@@ -495,19 +499,19 @@ func TestConvertExecutableExt(t *testing.T) {
 	}
 
 	installPath := "/.terraform.versions_test/"
-	test_array := []string{
+	testArray := []string{
 		"terraform",
 		"terraform.exe",
 		filepath.Join(homedir, installPath, "terraform"),
 		filepath.Join(homedir, installPath, "terraform.exe"),
 	}
 
-	for _, fpath := range test_array {
+	for _, fpath := range testArray {
 		fpathExt := ConvertExecutableExt((fpath))
 		outputMsg := fpath + " converted to " + fpathExt + " on " + runtime.GOOS
 
 		switch runtime.GOOS {
-		case "windows":
+		case windows:
 			if filepath.Ext(fpathExt) != ".exe" {
 				t.Error(outputMsg + " (unexpected)")
 				continue
diff --git a/lib/list_versions_test.go b/lib/list_versions_test.go
--- a/lib/list_versions_test.go
+++ b/lib/list_versions_test.go
@@ -51,14 +51,15 @@ const (
 
 // TestGetTFList : Get list from hashicorp
 func TestGetTFList(t *testing.T) {
-
-	list, _ := getTFList(hashiURL, true)
+	list, err := getTFList(hashiURL, true)
+	if err != nil {
+		t.Errorf("Error getting list of versions from %q: %v", hashiURL, err)
+	}
 
 	val := "0.1.0"
 	var exists bool
 
-	switch reflect.TypeOf(list).Kind() {
-	case reflect.Slice:
+	if reflect.TypeOf(list).Kind() == reflect.Slice {
 		s := reflect.ValueOf(list)
 
 		for i := 0; i < s.Len(); i++ {
@@ -73,7 +74,6 @@ func TestGetTFList(t *testing.T) {
 	} else {
 		t.Log("Write versions exist (expected)")
 	}
-
 }
 
 func compareLists(actual []string, expected []string) error {
@@ -95,11 +95,15 @@ func getMockListVersionServer() *httptest.Server {
 		case "/hashicorp/":
 			w.Header().Set("Content-Type", "text/html")
 			w.WriteHeader(http.StatusOK)
-			w.Write([]byte(hashicorpBody))
+			if _, err := w.Write([]byte(hashicorpBody)); err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+			}
 		case "/opentofu/":
 			w.Header().Set("Content-Type", "text/html")
 			w.WriteHeader(http.StatusOK)
-			w.Write([]byte(openTofuBody))
+			if _, err := w.Write([]byte(openTofuBody)); err != nil {
+				http.Error(w, err.Error(), http.StatusInternalServerError)
+			}
 		default:
 			http.NotFoundHandler().ServeHTTP(w, r)
 		}
@@ -213,7 +217,6 @@ func TestRemoveDuplicateVersions(t *testing.T) {
 // TestValidVersionFormat : test if func returns valid version format
 // more regex testing at https://rubular.com/r/UvWXui7EU2icSb
 func TestValidVersionFormat(t *testing.T) {
-
 	var version string
 	version = "0.11.8"
 
@@ -304,5 +307,4 @@ func TestValidVersionFormat(t *testing.T) {
 	} else {
 		t.Errorf("Failed to verify version format: %s\n", version)
 	}
-
 }
diff --git a/lib/lockfile_test.go b/lib/lockfile_test.go
--- a/lib/lockfile_test.go
+++ b/lib/lockfile_test.go
@@ -8,7 +8,7 @@ import (
 
 // Test Locking
 func TestLocking(t *testing.T) {
-	var lockFile string = ".tfswitch.lock"
+	lockFile := ".tfswitch.lock"
 	lockFilePath := filepath.Join(t.TempDir(), lockFile)
 
 	t.Logf("Testing lock acquirement: %s", lockFilePath)
diff --git a/lib/param_parsing/environment_test.go b/lib/param_parsing/environment_test.go
--- a/lib/param_parsing/environment_test.go
+++ b/lib/param_parsing/environment_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/parameters_test.go b/lib/param_parsing/parameters_test.go
--- a/lib/param_parsing/parameters_test.go
+++ b/lib/param_parsing/parameters_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -191,9 +192,9 @@ func TestGetParameters_dry_run_wont_download_anything(t *testing.T) {
 	installFileVersionPath := lib.ConvertExecutableExt(filepath.Join(installLocation, product.GetVersionPrefix()+params.Version))
 	// Make sure the file tfswitch WOULD download is absent
 	_ = os.Remove(installFileVersionPath)
-	lib.InstallProductVersion(product, params.DryRun, params.Version, params.CustomBinaryPath, params.InstallPath, params.MirrorURL, params.Arch)
-	if lib.FileExistsAndIsNotDir(installFileVersionPath) {
-		t.Error("Dry run should NOT download any files.")
+	err := lib.InstallProductVersion(product, params.DryRun, params.Version, params.CustomBinaryPath, params.InstallPath, params.MirrorURL, params.Arch)
+	if err != nil || lib.FileExistsAndIsNotDir(installFileVersionPath) {
+		t.Error("Dry run should NOT install any files.")
 	}
 	t.Cleanup(func() {
 		getopt.CommandLine = getopt.New()
@@ -210,7 +211,8 @@ func writeTestFile(t *testing.T, basePath string, fileName string, fileContent s
 	})
 }
 
-func checkExpectedPrecedenceVersion(t *testing.T, expectedVersion string, expectedDefaultVersion string) {
+//nolint:revive // FIXME: the 3rd argument is not used %-/ 10-Mar-2025
+func checkExpectedPrecedenceVersion(t *testing.T, expectedVersion string, _ string) {
 	getopt.CommandLine = getopt.New()
 	os.Args = []string{"cmd", "--chdir=../../test-data/skip-integration-tests/test_precedence"}
 	parameters := Params{}
diff --git a/lib/param_parsing/terraform_version_test.go b/lib/param_parsing/terraform_version_test.go
--- a/lib/param_parsing/terraform_version_test.go
+++ b/lib/param_parsing/terraform_version_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/terragrunt_test.go b/lib/param_parsing/terragrunt_test.go
--- a/lib/param_parsing/terragrunt_test.go
+++ b/lib/param_parsing/terragrunt_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -15,11 +16,20 @@ func TestGetVersionFromTerragrunt(t *testing.T) {
 	params.MirrorURL = lib.GetProductById("terraform").GetDefaultMirrorUrl()
 	params, err := GetVersionFromTerragrunt(params)
 	if err != nil {
-		t.Fatalf("Got error '%s'", err)
+		t.Errorf("Unexpected error: %v", err)
+	}
+	v1, v1Err := version.NewVersion("0.13")
+	if v1Err != nil {
+		t.Errorf("Error parsing v1 version: %v", v1Err)
+	}
+	v2, v2Err := version.NewVersion("0.14")
+	if v2Err != nil {
+		t.Errorf("Error parsing v2 version: %v", v2Err)
+	}
+	actualVersion, actualVersionErr := version.NewVersion(params.Version)
+	if actualVersionErr != nil {
+		t.Errorf("Error parsing actualVersion version: %v", actualVersionErr)
 	}
-	v1, _ := version.NewVersion("0.13")
-	v2, _ := version.NewVersion("0.14")
-	actualVersion, _ := version.NewVersion(params.Version)
 	if !actualVersion.GreaterThanOrEqual(v1) || !actualVersion.LessThan(v2) {
 		t.Error("Determined version is not between 0.13 and 0.14")
 	}
@@ -30,7 +40,10 @@ func TestGetVersionTerragrunt_with_no_terragrunt_file(t *testing.T) {
 	logger = lib.InitLogger("DEBUG")
 	params = initParams(params)
 	params.ChDirPath = "../../test-data/skip-integration-tests/test_no_file"
-	params, _ = GetVersionFromTerragrunt(params)
+	params, err := GetVersionFromTerragrunt(params)
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
 	if params.Version != "" {
 		t.Error("Version should be empty")
 	}
@@ -43,7 +56,7 @@ func TestGetVersionTerragrunt_with_no_version(t *testing.T) {
 	params.ChDirPath = "../../test-data/skip-integration-tests/test_terragrunt_no_version"
 	params, err := GetVersionFromTerragrunt(params)
 	if err != nil {
-		t.Fatalf("Got error '%s'", err)
+		t.Errorf("Unexpected error: %v", err)
 	}
 	if params.Version != "" {
 		t.Error("Version should be empty")
@@ -57,10 +70,10 @@ func TestGetVersionFromTerragrunt_erroneous_file(t *testing.T) {
 	params.ChDirPath = "../../test-data/skip-integration-tests/test_terragrunt_error_hcl"
 	params, err := GetVersionFromTerragrunt(params)
 	if err != nil {
-		t.Error(err)
+		t.Errorf("Unexpected error: %v", err)
 	}
 	expected := ""
 	if params.Version != expected {
-		t.Errorf("Expected version '%s', got '%s'", expected, params.Version)
+		t.Errorf("Expected version %q, got %q", expected, params.Version)
 	}
 }
diff --git a/lib/param_parsing/tfswitch_test.go b/lib/param_parsing/tfswitch_test.go
--- a/lib/param_parsing/tfswitch_test.go
+++ b/lib/param_parsing/tfswitch_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/toml_test.go b/lib/param_parsing/toml_test.go
--- a/lib/param_parsing/toml_test.go
+++ b/lib/param_parsing/toml_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
diff --git a/lib/param_parsing/versiontf_test.go b/lib/param_parsing/versiontf_test.go
--- a/lib/param_parsing/versiontf_test.go
+++ b/lib/param_parsing/versiontf_test.go
@@ -1,3 +1,4 @@
+//nolint:revive // FIXME: don't use an underscore in package name
 package param_parsing
 
 import (
@@ -11,12 +12,22 @@ import (
 func TestGetVersionFromVersionsTF_matches_version(t *testing.T) {
 	logger = lib.InitLogger("DEBUG")
 	var params Params
+	var getVerErr error
 	params = initParams(params)
 	params.ChDirPath = "../../test-data/integration-tests/test_versiontf"
 	params.MirrorURL = lib.GetProductById("terraform").GetDefaultMirrorUrl()
-	params, _ = GetVersionFromVersionsTF(params)
-	v1, _ := version.NewVersion("1.0.5")
-	actualVersion, _ := version.NewVersion(params.Version)
+	params, getVerErr = GetVersionFromVersionsTF(params)
+	if getVerErr != nil {
+		t.Errorf("Error getting version from Terraform module: %v", getVerErr)
+	}
+	v1, v1Err := version.NewVersion("1.0.5")
+	if v1Err != nil {
+		t.Errorf("Error parsing v1 version: %v", v1Err)
+	}
+	actualVersion, actualVersionErr := version.NewVersion(params.Version)
+	if actualVersionErr != nil {
+		t.Errorf("Error parsing actualVersion version: %v", actualVersionErr)
+	}
 	if !actualVersion.Equal(v1) {
 		t.Errorf("Determined version is not 1.0.5, but %s", params.Version)
 	}
diff --git a/lib/product_test.go b/lib/product_test.go
--- a/lib/product_test.go
+++ b/lib/product_test.go
@@ -48,6 +48,7 @@ func Test_GetId_Terraform(t *testing.T) {
 		t.Errorf("Product GetId does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetName_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetName()
@@ -55,6 +56,7 @@ func Test_GetName_Terraform(t *testing.T) {
 		t.Errorf("Product GetProductById does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetDefaultMirrorUrl_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetDefaultMirrorUrl()
@@ -62,6 +64,7 @@ func Test_GetDefaultMirrorUrl_Terraform(t *testing.T) {
 		t.Errorf("Product GetDefaultMirrorUrl does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetVersionPrefix_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetVersionPrefix()
@@ -69,6 +72,7 @@ func Test_GetVersionPrefix_Terraform(t *testing.T) {
 		t.Errorf("Product GetVersionPrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetExecutableName_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetExecutableName()
@@ -76,6 +80,7 @@ func Test_GetExecutableName_Terraform(t *testing.T) {
 		t.Errorf("Product GetExecutableName does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetArchivePrefix_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetArchivePrefix()
@@ -83,6 +88,7 @@ func Test_GetArchivePrefix_Terraform(t *testing.T) {
 		t.Errorf("Product GetArchivePrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetArtifactUrl_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetArtifactUrl("https://example.com/terraform", "5.3.2")
@@ -90,6 +96,7 @@ func Test_GetArtifactUrl_Terraform(t *testing.T) {
 		t.Errorf("Product GetArchivePrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetPublicKeyId_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetPublicKeyId()
@@ -97,6 +104,7 @@ func Test_GetPublicKeyId_Terraform(t *testing.T) {
 		t.Errorf("Product GetPublicKeyId does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetPublicKeyUrl_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetPublicKeyUrl()
@@ -104,6 +112,7 @@ func Test_GetPublicKeyUrl_Terraform(t *testing.T) {
 		t.Errorf("Product GetPublicKeyUrl does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetShaSignatureSuffix_Terraform(t *testing.T) {
 	product := GetProductById("terraform")
 	actual := product.GetShaSignatureSuffix()
@@ -111,8 +120,9 @@ func Test_GetShaSignatureSuffix_Terraform(t *testing.T) {
 		t.Errorf("Product GetShaSignatureSuffix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetRecentVersionProduct_Terraform(t *testing.T) {
-	var recentFile RecentFile = RecentFile{
+	recentFile := RecentFile{
 		OpenTofu:  []string{"1.2.3", "3.2.1"},
 		Terraform: []string{"5.4.3", "3.4.5"},
 	}
@@ -125,8 +135,9 @@ func Test_GetRecentVersionProduct_Terraform(t *testing.T) {
 		t.Error(err)
 	}
 }
+
 func Test_SetRecentVersionProduct_Terraform(t *testing.T) {
-	var recentFile RecentFile = RecentFile{
+	recentFile := RecentFile{
 		OpenTofu:  []string{"1.2.3", "3.2.1"},
 		Terraform: []string{"5.4.3", "3.4.5"},
 	}
@@ -153,6 +164,7 @@ func Test_GetId_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetId does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetName_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetName()
@@ -160,6 +172,7 @@ func Test_GetName_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetProductById does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetDefaultMirrorUrl_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetDefaultMirrorUrl()
@@ -167,6 +180,7 @@ func Test_GetDefaultMirrorUrl_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetDefaultMirrorUrl does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetVersionPrefix_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetVersionPrefix()
@@ -174,6 +188,7 @@ func Test_GetVersionPrefix_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetVersionPrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetExecutableName_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetExecutableName()
@@ -181,6 +196,7 @@ func Test_GetExecutableName_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetExecutableName does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetArchivePrefix_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetArchivePrefix()
@@ -188,6 +204,7 @@ func Test_GetArchivePrefix_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetArchivePrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetArtifactUrl_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetArtifactUrl("https://example.com/opentofu", "5.3.2")
@@ -195,6 +212,7 @@ func Test_GetArtifactUrl_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetArchivePrefix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetPublicKeyId_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetPublicKeyId()
@@ -202,6 +220,7 @@ func Test_GetPublicKeyId_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetPublicKeyId does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetPublicKeyUrl_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetPublicKeyUrl()
@@ -209,6 +228,7 @@ func Test_GetPublicKeyUrl_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetPublicKeyUrl does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetShaSignatureSuffix_OpenTofu(t *testing.T) {
 	product := GetProductById("opentofu")
 	actual := product.GetShaSignatureSuffix()
@@ -216,8 +236,9 @@ func Test_GetShaSignatureSuffix_OpenTofu(t *testing.T) {
 		t.Errorf("Product GetShaSignatureSuffix does not match expected ID. Expected: %q, actual: %q", expected, actual)
 	}
 }
+
 func Test_GetRecentVersionProduct_OpenTofu(t *testing.T) {
-	var recentFile RecentFile = RecentFile{
+	recentFile := RecentFile{
 		Terraform: []string{"1.2.3", "3.2.1"},
 		OpenTofu:  []string{"5.4.3", "3.4.5"},
 	}
@@ -230,8 +251,9 @@ func Test_GetRecentVersionProduct_OpenTofu(t *testing.T) {
 		t.Error(err)
 	}
 }
+
 func Test_SetRecentVersionProduct_OpenTofu(t *testing.T) {
-	var recentFile RecentFile = RecentFile{
+	recentFile := RecentFile{
 		Terraform: []string{"1.2.3", "3.2.1"},
 		OpenTofu:  []string{"5.4.3", "3.4.5"},
 	}
diff --git a/lib/recent_test.go b/lib/recent_test.go
--- a/lib/recent_test.go
+++ b/lib/recent_test.go
@@ -94,9 +94,11 @@ func performUnmarshalRecentFileDataTest(t *testing.T, recentFileContent string,
 	defer os.RemoveAll(temp)
 	pathToTempFile := filepath.Join(temp, "recent.json")
 
-	os.WriteFile(pathToTempFile, []byte(recentFileContent), 0600)
+	if err := os.WriteFile(pathToTempFile, []byte(recentFileContent), 0o600); err != nil {
+		t.Errorf("Could not write to temporary file %q: %v", pathToTempFile, err)
+	}
 
-	var recentFileData = RecentFile{}
+	recentFileData := RecentFile{}
 	unmarshalRecentFileData(pathToTempFile, &recentFileData)
 	t.Log("Comparing Terraform versions")
 	assert.Equal(t, expectedRecentFileData.Terraform, recentFileData.Terraform)
@@ -105,7 +107,7 @@ func performUnmarshalRecentFileDataTest(t *testing.T, recentFileContent string,
 }
 
 func Test_saveFile(t *testing.T) {
-	var recentFileData = RecentFile{
+	recentFileData := RecentFile{
 		Terraform: []string{"1.2.3", "4.5.6"},
 		OpenTofu:  []string{"6.6.6"},
 	}
@@ -114,7 +116,7 @@ func Test_saveFile(t *testing.T) {
 		t.Errorf("Could not create temporary directory")
 	}
 	defer func(path string) {
-		_ = os.RemoveAll(temp)
+		_ = os.RemoveAll(path)
 	}(temp)
 	pathToTempFile := filepath.Join(temp, "recent.json")
 	saveRecentFile(recentFileData, pathToTempFile)
@@ -187,7 +189,7 @@ func Test_addRecent(t *testing.T) {
 
 func Test_prependExistingVersionIsMovingToTop(t *testing.T) {
 	product := GetProductById("terraform")
-	var recentFileData = RecentFile{
+	recentFileData := RecentFile{
 		Terraform: []string{"1.2.3", "4.5.6", "7.7.7"},
 		OpenTofu:  []string{"6.6.6"},
 	}
@@ -206,7 +208,7 @@ func Test_prependExistingVersionIsMovingToTop(t *testing.T) {
 
 func Test_prependNewVersion(t *testing.T) {
 	product := GetProductById("terraform")
-	var recentFileData = RecentFile{
+	recentFileData := RecentFile{
 		Terraform: []string{"1.2.3", "4.5.6", "4.5.7", "4.5.8", "4.5.9"},
 		OpenTofu:  []string{"6.6.6"},
 	}
diff --git a/lib/semver_test.go b/lib/semver_test.go
--- a/lib/semver_test.go
+++ b/lib/semver_test.go
@@ -16,77 +16,85 @@ var versionsRaw = []string{
 	"0.7.1",
 	"1.4-beta",
 	"1.4",
-	"2"}
+	"2",
+}
 
 // TestSemverParser1 : Test to see if SemVerParser parses valid version
 // Test version 1.1
 func TestSemverParserCase1(t *testing.T) {
-
 	tfconstraint := "1.1"
-	tfversion, _ := lib.SemVerParser(&tfconstraint, versionsRaw)
+	tfversion, semVerErr := lib.SemVerParser(&tfconstraint, versionsRaw)
+	if semVerErr != nil {
+		t.Errorf("Error parsing version %q: %v", tfconstraint, semVerErr)
+	}
 	expected := "1.1.0"
 	if tfversion == expected {
-		t.Logf("Version exist in list %v [expected]", expected)
+		t.Logf("Version %q exists in list [expected]", expected)
 	} else {
-		t.Logf("Version does not exist in list %v [unexpected]", tfconstraint)
-		t.Errorf("This is unexpected. Parsing failed. Expected: %v", expected)
+		t.Logf("Version %q does not exist in list [unexpected]", tfconstraint)
+		t.Errorf("This is unexpected. Parsing failed. Expected: %q", expected)
 	}
 }
 
 // TestSemverParserCase2 : Test to see if SemVerParser parses valid version
 // Test version ~> 1.1 should return  1.1.4
 func TestSemverParserCase2(t *testing.T) {
-
 	tfconstraint := "~> 1.1.0"
-	tfversion, _ := lib.SemVerParser(&tfconstraint, versionsRaw)
+	tfversion, semVerErr := lib.SemVerParser(&tfconstraint, versionsRaw)
+	if semVerErr != nil {
+		t.Errorf("Error parsing version %q: %v", tfconstraint, semVerErr)
+	}
 	expected := "1.1.4"
 	if tfversion == expected {
-		t.Logf("Version exist in list %v [expected]", expected)
+		t.Logf("Version %q exist in list [expected]", expected)
 	} else {
-		t.Logf("Version does not exist in list %v [unexpected]", tfconstraint)
-		t.Errorf("This is unexpected. Parsing failed. Expected: %v", expected)
+		t.Logf("Version %q does not exist in list [unexpected]", tfconstraint)
+		t.Errorf("This is unexpected. Parsing failed. Expected: %q", expected)
 	}
 }
 
 // TestSemverParserCase3 : Test to see if SemVerParser parses valid version
 // Test version ~> 1.1 should return  1.1.4
 func TestSemverParserCase3(t *testing.T) {
-
 	tfconstraint := "~> 1.A.0"
 	_, err := lib.SemVerParser(&tfconstraint, versionsRaw)
 	if err != nil {
-		t.Logf("This test is suppose to error %v [expected]", tfconstraint)
+		t.Logf("This test is supposed to error on %q [expected]", tfconstraint)
 	} else {
-		t.Errorf("This test is suppose to error but passed %v [expected]", tfconstraint)
+		t.Errorf("This test is supposed to error on %q but passed [unexpected]", tfconstraint)
 	}
 }
 
 // TestSemverParserCase4 : Test to see if SemVerParser parses valid version
 // Test version ~> >= 1.0, < 1.4 should return  1.3.0
 func TestSemverParserCase4(t *testing.T) {
-
 	tfconstraint := ">= 1.0, < 1.4"
-	tfversion, _ := lib.SemVerParser(&tfconstraint, versionsRaw)
+	tfversion, semVerErr := lib.SemVerParser(&tfconstraint, versionsRaw)
+	if semVerErr != nil {
+		t.Errorf("Error parsing version %q: %v", tfconstraint, semVerErr)
+	}
 	expected := "1.3.0"
 	if tfversion == expected {
-		t.Logf("Version exist in list %v [expected]", expected)
+		t.Logf("Version %q exist in list [expected]", expected)
 	} else {
-		t.Logf("Version does not exist in list %v [unexpected]", tfconstraint)
-		t.Errorf("This is unexpected. Parsing failed. Expected: %v", expected)
+		t.Logf("Version %q does not exist in list [unexpected]", tfconstraint)
+		t.Errorf("This is unexpected. Parsing failed. Expected: %q", expected)
 	}
 }
 
 // TestSemverParserCase5 : Test to see if SemVerParser parses valid version
 // Test version ~> >= 1.0 should return  2.0.0
 func TestSemverParserCase5(t *testing.T) {
-
 	tfconstraint := ">= 1.0"
-	tfversion, _ := lib.SemVerParser(&tfconstraint, versionsRaw)
+	tfversion, semVerErr := lib.SemVerParser(&tfconstraint, versionsRaw)
+	if semVerErr != nil {
+		t.Errorf("Error parsing version %q: %v", tfconstraint, semVerErr)
+	}
 	expected := "2.0.0"
 	if tfversion == expected {
-		t.Logf("Version exist in list %v [expected]", expected)
+		t.Logf("Version %q exist in list [expected]", expected)
 	} else {
-		t.Logf("Version does not exist in list %v [unexpected]", tfconstraint)
-		t.Errorf("This is unexpected. Parsing failed. Expected: %v", expected)
+		t.Logf("Version %q does not exist in list [unexpected]", tfconstraint)
+		t.Errorf("This is unexpected. Parsing failed. Expected: %q", expected)
 	}
 }
diff --git a/lib/symlink_test.go b/lib/symlink_test.go
--- a/lib/symlink_test.go
+++ b/lib/symlink_test.go
@@ -12,11 +12,10 @@ import (
 // TestCreateSymlink : check if symlink exist-remove if exist,
 // create symlink, check if symlink exist, remove symlink
 func TestCreateSymlink(t *testing.T) {
-
 	testSymlinkDest := "/test-tfswitcher-dest"
 	testSymlinkSrc := "/test-tfswitcher-src"
-	if runtime.GOOS == "windows" {
-		testSymlinkSrc = "/test-tfswitcher-src.exe"
+	if runtime.GOOS == windows {
+		testSymlinkSrc += ".exe"
 	}
 
 	home, err := homedir.Dir()
@@ -33,8 +32,8 @@ func TestCreateSymlink(t *testing.T) {
 	}
 	defer create.Close()
 
-	if runtime.GOOS != "windows" {
-		ln, _ := os.Readlink(symlinkPathSrc)
+	if runtime.GOOS != windows {
+		ln, _ := os.Readlink(symlinkPathSrc) // nolint:errcheck // covered by conditional below
 
 		if ln != symlinkPathDest {
 			t.Logf("Symlink does not exist %v [expected]", ln)
@@ -45,9 +44,12 @@ func TestCreateSymlink(t *testing.T) {
 		}
 	}
 
-	CreateSymlink(symlinkPathDest, symlinkPathSrc)
+	lnCreateErr := CreateSymlink(symlinkPathDest, symlinkPathSrc)
+	if lnCreateErr != nil {
+		t.Errorf("Could not create symlink at %q to %q: %v", symlinkPathSrc, symlinkPathDest, lnCreateErr)
+	}
 
-	if runtime.GOOS == "windows" {
+	if runtime.GOOS == windows {
 		_, err := os.Stat(symlinkPathSrc)
 		if err != nil {
 			t.Logf("Could not stat file copy at %v. [unexpected]", symlinkPathSrc)
@@ -56,7 +58,7 @@ func TestCreateSymlink(t *testing.T) {
 			t.Logf("File copy exists at %v [expected]", symlinkPathSrc)
 		}
 	} else {
-		lnCheck, _ := os.Readlink(symlinkPathSrc)
+		lnCheck, _ := os.Readlink(symlinkPathSrc) // nolint:errcheck // covered by conditional below
 		if lnCheck == symlinkPathDest {
 			t.Logf("Symlink exist %v [expected]", lnCheck)
 		} else {
@@ -65,16 +67,20 @@ func TestCreateSymlink(t *testing.T) {
 		}
 	}
 
-	_ = os.Remove(symlinkPathSrc)
-	_ = os.Remove(symlinkPathDest)
+	symlinkPathSrcErr := os.Remove(symlinkPathSrc)
+	if symlinkPathSrcErr != nil {
+		t.Logf("Could not remove %q: %v [internal failure]", symlinkPathSrc, symlinkPathSrcErr)
+	}
+	symlinkPathDestErr := os.Remove(symlinkPathDest)
+	if symlinkPathDestErr != nil {
+		t.Logf("Could not remove %q: %v [internal failure]", symlinkPathDest, symlinkPathDestErr)
+	}
 }
 
 // TestRemoveSymlink : check if symlink exist-create if does not exist,
 // remove symlink, check if symlink exist
 func TestRemoveSymlink(t *testing.T) {
-
 	testSymlinkSrc := "/test-tfswitcher-src"
-
 	testSymlinkDest := "/test-tfswitcher-dest"
 
 	homedir, errCurr := homedir.Dir()
@@ -84,7 +90,7 @@ func TestRemoveSymlink(t *testing.T) {
 	symlinkPathSrc := filepath.Join(homedir, testSymlinkSrc)
 	symlinkPathDest := filepath.Join(homedir, testSymlinkDest)
 
-	ln, _ := os.Readlink(symlinkPathSrc)
+	ln, _ := os.Readlink(symlinkPathSrc) // nolint:errcheck // covered by conditional below
 
 	if ln != symlinkPathDest {
 		t.Logf("Symlink does exist %v [expected]", ln)
@@ -94,9 +100,8 @@ func TestRemoveSymlink(t *testing.T) {
 		}
 	}
 
-	RemoveSymlink(symlinkPathSrc)
-
-	lnCheck, _ := os.Readlink(symlinkPathSrc)
+	RemoveSymlink(symlinkPathSrc)             // nolint:errcheck // covered by conditional below
+	lnCheck, _ := os.Readlink(symlinkPathSrc) // nolint:errcheck // covered by conditional below
 	if lnCheck == symlinkPathDest {
 		t.Logf("Symlink should not exist %v [unexpected]", lnCheck)
 		t.Error("Symlink was not removed")
@@ -107,10 +112,8 @@ func TestRemoveSymlink(t *testing.T) {
 
 // TestCheckSymlink : Create symlink, test if file is symlink
 func TestCheckSymlink(t *testing.T) {
-
-	testSymlinkSrc := "/test-tgshifter-src"
-
-	testSymlinkDest := "/test-tgshifter-dest"
+	testSymlinkSrc := "/test-tfswitcher-src"
+	testSymlinkDest := "/test-tfswitcher-dest"
 
 	homedir, errCurr := homedir.Dir()
 	if errCurr != nil {
@@ -119,7 +122,7 @@ func TestCheckSymlink(t *testing.T) {
 	symlinkPathSrc := filepath.Join(homedir, testSymlinkSrc)
 	symlinkPathDest := filepath.Join(homedir, testSymlinkDest)
 
-	ln, _ := os.Readlink(symlinkPathSrc)
+	ln, _ := os.Readlink(symlinkPathSrc) // nolint:errcheck // it is okay to ignore error here
 
 	if ln != symlinkPathDest {
 		t.Log("Creating symlink")
@@ -136,5 +139,8 @@ func TestCheckSymlink(t *testing.T) {
 		t.Logf("Symlink does not exist %v [unexpected]", ln)
 	}
 
-	_ = os.Remove(symlinkPathSrc)
+	symlinkPathSrcErr := os.Remove(symlinkPathSrc)
+	if symlinkPathSrcErr != nil {
+		t.Logf("Could not remove %q: %v [internal failure]", symlinkPathSrc, symlinkPathSrcErr)
+	}
 }