diff --git a/.actrc b/.actrc
new file mode 100644
index 0000000..0ad3da7
--- /dev/null
+++ b/.actrc
@@ -0,0 +1,10 @@
+--use-new-action-cache
+--action-cache-path=.github/cache/act/actions
+--cache-server-path=.github/cache/act/cache
+--artifact-server-path=.github/cache/act/artifacts
+--artifact-server-port=34018
+--platform self-hosted=ghcr.io/catthehacker/ubuntu:act-latest
+--platform ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest
+--platform ubuntu-22.04=ghcr.io/catthehacker/ubuntu:act-22.04
+--platform ubuntu-20.04=ghcr.io/catthehacker/ubuntu:act-20.04
+--platform ubuntu-18.04=ghcr.io/catthehacker/ubuntu:act-18.04
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 969e5e1..c4c223f 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -1,12 +1,20 @@
 name: Tests
 
+permissions:
+  contents: read
+  packages: write
+
 on:
-  push:
+  workflow_call:
   workflow_dispatch:
-  pull_request:
+  push:
+    branches:
+      - main
+  schedule:
+    - cron: "0 14 * * 2" # 2pm Patch Tuesday
 
 concurrency:
-  group: tests-${{ github.head_ref || github.run_id }}
+  group: ${{ github.head_ref || github.run_id }}
   cancel-in-progress: true
 
 jobs:
diff --git a/.github/workflows/trunk.cache.yml b/.github/workflows/trunk.cache.yml
new file mode 100644
index 0000000..6e3c66f
--- /dev/null
+++ b/.github/workflows/trunk.cache.yml
@@ -0,0 +1,36 @@
+name: Trunk Cache
+
+permissions: read-all
+
+on:
+  workflow_call:
+  workflow_dispatch:
+  push:
+    branches:
+      - main
+    paths:
+      - .trunk/trunk.yaml
+  schedule:
+    - cron: "0 9 * * 1" # 9am Tooling Monday
+
+concurrency:
+  group: ${{ github.head_ref || github.run_id }}
+  cancel-in-progress: true
+
+jobs:
+  trunk-cache:
+    name: Trunk Cache
+    runs-on: ubuntu-latest
+    permissions:
+      actions: write
+    steps:
+      - name: "Setup PHP"
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: 8.3
+      - name: "Checkout"
+        uses: actions/checkout@v4
+      - name: "Trunk Cache"
+        uses: trunk-io/trunk-action@v1
+        with:
+          check-mode: populate_cache_only
diff --git a/.github/workflows/trunk.check.yml b/.github/workflows/trunk.check.yml
new file mode 100644
index 0000000..2e06a65
--- /dev/null
+++ b/.github/workflows/trunk.check.yml
@@ -0,0 +1,33 @@
+name: Trunk Check
+
+permissions: read-all
+
+on:
+  workflow_call:
+  workflow_dispatch:
+  push:
+    branches:
+      - main
+  schedule:
+    - cron: "0 11 * * 2" # 11am Patch Tuesday
+
+concurrency:
+  group: ${{ github.head_ref || github.run_id }}
+  cancel-in-progress: true
+
+jobs:
+  trunk-check:
+    name: Trunk Check Runner
+    runs-on: ubuntu-latest
+    permissions:
+      checks: write # For trunk to post annotations
+      contents: read # For repo checkout
+    steps:
+      - name: "Setup PHP"
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: 8.3
+      - name: "Checkout"
+        uses: actions/checkout@v4
+      - name: "Trunk Check"
+        uses: trunk-io/trunk-action@v1
diff --git a/.github/workflows/trunk.upgrade.yml b/.github/workflows/trunk.upgrade.yml
new file mode 100644
index 0000000..cc870b3
--- /dev/null
+++ b/.github/workflows/trunk.upgrade.yml
@@ -0,0 +1,47 @@
+name: Trunk Upgrade
+
+permissions: read-all
+
+on:
+  workflow_call:
+  workflow_dispatch:
+  push:
+    branches:
+      - main
+    paths:
+      - .trunk/trunk.yaml
+      - .github/workflows/trunk.upgrade.yml
+  schedule:
+    - cron: "0 11 * * 1" # 11am Tooling Monday
+
+concurrency:
+  group: ${{ github.head_ref || github.run_id }}
+  cancel-in-progress: true
+
+jobs:
+  trunk-upgrade:
+    name: Upgrade Trunk
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write # For trunk to create PRs
+      pull-requests: write # For trunk to create PRs
+    steps:
+      - name: "Setup PHP"
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: 8.3
+      - name: "Checkout"
+        uses: actions/checkout@v4
+      - name: "Trunk Upgrade"
+        uses: trunk-io/trunk-action/upgrade@v1
+      - name: "PR: Find Pull Request"
+        uses: juliangruber/find-pull-request-action@v1
+        id: find-pull-request
+        with:
+          labels: trunk
+      - name: "PR: Enable Pull Request Automerge"
+        continue-on-error: true
+        uses: peter-evans/enable-pull-request-automerge@v3
+        with:
+          token: ${{ secrets.GITHUB_TOKEN }}
+          pull-request-number: ${{ steps.find-pull-request.outputs.number }}
diff --git a/.gitignore b/.gitignore
index 8eb18a5..bcc0cea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
 /vendor/
 /.idea
-/.github/act.secrets
-/composer.lock
\ No newline at end of file
+/.secrets
+/composer.lock
diff --git a/.trunk/configs/.checkov.yaml b/.trunk/configs/.checkov.yaml
new file mode 100644
index 0000000..8331ca9
--- /dev/null
+++ b/.trunk/configs/.checkov.yaml
@@ -0,0 +1,3 @@
+---
+skip-check:
+  - CKV_SECRET_* # Skip all checks that start with CKV_SECRET, we already have gitleaks doing this.
diff --git a/.trunk/configs/.gitleaks.toml b/.trunk/configs/.gitleaks.toml
new file mode 100644
index 0000000..0ba3b68
--- /dev/null
+++ b/.trunk/configs/.gitleaks.toml
@@ -0,0 +1,3 @@
+title = "Gitleaks config"
+[extend]
+useDefault = true
diff --git a/.trunk/configs/.gitleaksignore b/.trunk/configs/.gitleaksignore
new file mode 100644
index 0000000..e69de29
diff --git a/.trunk/configs/.hadolint.yaml b/.trunk/configs/.hadolint.yaml
new file mode 100644
index 0000000..d700141
--- /dev/null
+++ b/.trunk/configs/.hadolint.yaml
@@ -0,0 +1,3 @@
+ignored:
+  - DL3006
+  - DL3008
diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml
new file mode 100644
index 0000000..fb94039
--- /dev/null
+++ b/.trunk/configs/.markdownlint.yaml
@@ -0,0 +1,10 @@
+# Autoformatter friendly markdownlint config (all formatting rules disabled)
+default: true
+blank_lines: false
+bullet: false
+html: false
+indentation: false
+line_length: false
+spaces: false
+url: false
+whitespace: false
diff --git a/.trunk/configs/.markdownlintignore b/.trunk/configs/.markdownlintignore
new file mode 100644
index 0000000..bf789ea
--- /dev/null
+++ b/.trunk/configs/.markdownlintignore
@@ -0,0 +1 @@
+LICENCE.md
diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc
new file mode 100644
index 0000000..8cc03cd
--- /dev/null
+++ b/.trunk/configs/.shellcheckrc
@@ -0,0 +1,6 @@
+enable=all
+source-path=SCRIPTDIR
+
+# If you're having issues with shellcheck following source, disable the errors via:
+# disable=SC1090
+# disable=SC1091
diff --git a/.trunk/configs/.tflint.hcl b/.trunk/configs/.tflint.hcl
new file mode 100644
index 0000000..7488b8c
--- /dev/null
+++ b/.trunk/configs/.tflint.hcl
@@ -0,0 +1,16 @@
+config {
+    format = "compact"
+    module = true
+    plugin_dir = "~/.tflint.d/plugins"
+}
+
+plugin "terraform" {
+    enabled = true
+    preset  = "recommended"
+}
+
+plugin "aws" {
+    enabled = true
+    version = "0.27.0"
+    source  = "github.com/terraform-linters/tflint-ruleset-aws"
+}
diff --git a/.trunk/configs/.trivyignore b/.trunk/configs/.trivyignore
new file mode 100644
index 0000000..074990f
--- /dev/null
+++ b/.trunk/configs/.trivyignore
@@ -0,0 +1,2 @@
+AVD-DS-0001
+AVD-DS-0002
diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml
index 184e251..984573e 100644
--- a/.trunk/configs/.yamllint.yaml
+++ b/.trunk/configs/.yamllint.yaml
@@ -1,7 +1,15 @@
+extends: relaxed
 rules:
   quoted-strings:
     required: only-when-needed
-    extra-allowed: ["{|}"]
+    extra-allowed: ["{|*}"]
+  empty-values:
+    forbid-in-block-mappings: false
+    forbid-in-flow-mappings: false
+    ignore:
+      - .github/workflows/*.yml
   key-duplicates: {}
   octal-values:
     forbid-implicit-octal: true
+  document-start: disable
+  line-length: disable
diff --git a/.trunk/configs/svgo.config.js b/.trunk/configs/svgo.config.js
new file mode 100644
index 0000000..b257d13
--- /dev/null
+++ b/.trunk/configs/svgo.config.js
@@ -0,0 +1,14 @@
+module.exports = {
+  plugins: [
+    {
+      name: "preset-default",
+      params: {
+        overrides: {
+          removeViewBox: false, // https://github.com/svg/svgo/issues/1128
+          sortAttrs: true,
+          removeOffCanvasPaths: true,
+        },
+      },
+    },
+  ],
+};
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
index 510ed6d..e98156c 100644
--- a/.trunk/trunk.yaml
+++ b/.trunk/trunk.yaml
@@ -2,31 +2,58 @@
 # To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
 version: 0.1
 cli:
-  version: 1.21.0
+  version: 1.22.1
 # Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
 plugins:
   sources:
     - id: trunk
-      ref: v1.4.5
+      ref: v1.5.0
       uri: https://github.com/trunk-io/plugins
 # Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
 runtimes:
   enabled:
+    - go@1.21.0
     - node@18.12.1
     - python@3.10.8
 # This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
 lint:
   enabled:
-    - actionlint@1.6.27
-    - checkov@3.2.60
+    - gitleaks@8.18.2
+    - markdownlint@0.40.0
+    - taplo@0.8.1
+    - actionlint@1.7.0
+    - checkov@3.2.92
     - git-diff-check
     - prettier@3.2.5
-    - trivy@0.50.1
-    - trufflehog@3.71.0
+    - trivy@0.51.1
+    - trufflehog@3.76.2
     - yamllint@1.35.1
+  definitions:
+    - name: markdownlint
+      direct_configs:
+        - .markdownlintignore
+        - .markdownlint.yaml
 actions:
+  disabled:
+    - trunk-upgrade-available
   enabled:
     - trunk-announce
     - trunk-check-pre-push
     - trunk-fmt-pre-commit
-    - trunk-upgrade-available
+tools:
+  enabled:
+    - tfupdate@0.8.2
+    - phpstan@1.10.58
+    - gh@2.49.2
+    - jq@jq-1.7.1
+    - yq@4.44.1
+    - awscli@1.32.107
+    - action-validator@0.6.0
+    - act@0.2.62
+    - shellcheck@0.10.0
+    - hadolint@2.12.0
+    - svgo@3.3.2
+    - tofu@1.7.1
+    - trunk-toolbox@0.3.1
+    - tflint@0.51.1
+    - terraform@1.1.4
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 90e43cb..e0cc98e 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -1,19 +1,21 @@
+# Code of Conduct
+
 This code of conduct outlines our expectations for participants within the open source community. Anyone who violates this code of conduct may be banned from contributing here.
 
-# Requirements
+## Requirements
 
 - **Be friendly and patient.**
 - **Be welcoming** _We strive to be a community that welcomes and supports people of all backgrounds and identities._
 - **Be respectful** _Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners._
 
-# Unacceptable Behaviour
+## Unacceptable Behaviour
 
 - Offensive comments related to gender, sexual orientation, disability, mental illness, physical appearance, body size, race, age, regional discrimination, political or religious affiliation.
 - Threats of violence, both physical and psycological.
 - Incitement of violence towards any individual, including encouraging a person to commit suicide or to engage in self-harm.
 - Continued communication after requests to cease.
 
-# Interactions
+## Interactions
 
 - Don't just tell somebody they are wrong, or what they have done is wrong. You must always explain what is wrong, and why it is wrong.
 - Don't reject contributions that are partially complete and then go and commit your own version. Try to work with the author to complete their work.
diff --git a/LICENSE.md b/LICENCE.md
similarity index 100%
rename from LICENSE.md
rename to LICENCE.md