diff --git a/.cz.toml b/.cz.toml
new file mode 100644
index 0000000..7866eab
--- /dev/null
+++ b/.cz.toml
@@ -0,0 +1,6 @@
+[tool.commitizen]
+name = "cz_conventional_commits"
+version_provider = "scm"
+update_changelog_on_bump = true
+major_version_zero = true
+tag_format = "v$version"
diff --git a/.gitea/workflows/development.yml b/.gitea/workflows/development.yml
new file mode 100644
index 0000000..19cb03e
--- /dev/null
+++ b/.gitea/workflows/development.yml
@@ -0,0 +1,26 @@
+---
+name: development
+on:
+ push:
+ branches-ignore:
+ - main
+
+jobs:
+ commit-check:
+ name: Check commit compliance
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install commitizen
+ run: pip3 install commitizen
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - name: Verify commit message compliance
+ run: |
+ echo "cz check --message '${{ github.event.head_commit.message }}'"
+ cz check --message "${{ github.event.head_commit.message }}"
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
diff --git a/.gitea/workflows/pull-request-open.yml b/.gitea/workflows/pull-request-open.yml
new file mode 100644
index 0000000..af6d4fd
--- /dev/null
+++ b/.gitea/workflows/pull-request-open.yml
@@ -0,0 +1,128 @@
+---
+name: pull-requests-open
+on:
+ pull_request:
+ types:
+ - opened
+ - edited
+ - synchronize
+ branches:
+ - main
+
+jobs:
+ commit-history-check:
+ name: Check commit compliance
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.sha }}
+ fetch-depth: 0
+
+ - name: Install commitizen
+ run: pip3 install commitizen
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - run: git log origin/${{ github.event.pull_request.base.ref }}..
+
+ - name: Verify commit message compliance
+ run: |
+ echo "cz check --rev-range origin/${{ gitea.event.pull_request.base.ref }}.."
+ cz check --rev-range origin/${{ gitea.event.pull_request.base.ref }}..
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ pre-commit-check:
+ name: Check pre-commit status
+ runs-on: ubuntu-latest
+ needs: commit-history-check
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install pre-commit
+ run: pip3 install pre-commit
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - name: Install pre-commit dependencies
+ run: |
+ # terraform-docs
+ curl -sSLo /tmp/terraform-docs.tar.gz \
+ https://terraform-docs.io/dl/${TERRAFORM_DOCS_VERSION}/terraform-docs-${TERRAFORM_DOCS_VERSION}-$(uname)-amd64.tar.gz
+ tar -xzf /tmp/terraform-docs.tar.gz -C /tmp
+ chmod +x /tmp/terraform-docs
+ mv /tmp/terraform-docs /usr/local/bin/terraform-docs
+ rm -rf /tmp/*
+
+ # opentofu
+ curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh \
+ -o install-opentofu.sh
+ chmod +x install-opentofu.sh
+ ./install-opentofu.sh --install-method standalone --opentofu-version $OPENTOFU_VERSION
+ rm -f install-opentofu.sh
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+ env:
+ OPENTOFU_VERSION: 1.8.0
+ TERRAFORM_DOCS_VERSION: v0.18.0
+
+ - name: Verify pre-commit status
+ run: pre-commit run --all
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ end-to-end-tests:
+ name: Run E2E tofu tests
+ runs-on: ubuntu-latest
+ needs: pre-commit-check
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Install required packages
+ run: |
+ export DEBIAN_FRONTEND=noninteractive
+ sudo apt update
+ sudo apt install -y curl jq
+
+ curl https://vault.ednz.fr/v1/ednz-root-ca/ca -o /tmp/ednz_ca
+ openssl x509 -inform DER -in /tmp/ednz_ca -out /usr/local/share/ca-certificates/ednz_ca.crt -outform pem
+ update-ca-certificates
+
+ - name: Install OpenTofu
+ uses: opentofu/setup-opentofu@v1
+ with:
+ tofu_version: 1.8.2
+
+ - name: Get secrets from vault
+ id: import-secrets
+ uses: hashicorp/vault-action@v3
+ with:
+ url: "https://vault.ednz.fr"
+ method: approle
+ roleId: ${{ secrets.VAULT_APPROLE_ID }}
+ secretId: ${{ secrets.VAULT_APPROLE_SECRET_ID }}
+ secrets: |
+ kv/data/cicd/vault/infrabuilder approle_id | VAULT_INFRABUILDER_APPROLE_ID ;
+ kv/data/cicd/vault/infrabuilder approle_secret_id | VAULT_INFRABUILDER_APPROLE_SECRET_ID ;
+
+ - name: Get required credentials
+ id: tofu-auth
+ run: |
+ VAULT_TOKEN=$(curl --silent --request POST --data '{"role_id": "${{ steps.import-secrets.outputs.VAULT_INFRABUILDER_APPROLE_ID }}","secret_id": "${{ steps.import-secrets.outputs.VAULT_INFRABUILDER_APPROLE_SECRET_ID }}"}' https://vault.ednz.fr/v1/auth/approle/login | jq -r .auth.client_token)
+ echo "vault_token=$VAULT_TOKEN" >> $GITHUB_OUTPUT
+
+ - name: Tofu init
+ run: tofu init
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - name: Tofu test
+ run: tofu test
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+ env:
+ VAULT_TOKEN: ${{ steps.tofu-auth.outputs.vault_token }}
diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml
new file mode 100644
index 0000000..472ddaa
--- /dev/null
+++ b/.gitea/workflows/release.yml
@@ -0,0 +1,54 @@
+---
+name: build-deploy
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ do-release:
+ if: "!startsWith(github.event.head_commit.message, 'bump:')"
+ runs-on: ubuntu-latest
+ name: Bump version and create changelog with commitizen
+ steps:
+ - name: Get secrets from vault
+ id: import-secrets
+ uses: hashicorp/vault-action@v3
+ with:
+ url: "https://vault.ednz.fr"
+ method: approle
+ roleId: ${{ secrets.VAULT_APPROLE_ID }}
+ secretId: ${{ secrets.VAULT_APPROLE_SECRET_ID }}
+ secrets: |
+ kv/data/applications/gitea/users/actions username | GITEA_ACTIONS_USERNAME ;
+ kv/data/applications/gitea/users/actions token_write | GITEA_ACTIONS_TOKEN ;
+
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ token: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_TOKEN }}
+
+ - name: Install commitizen
+ run: pip3 install commitizen
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - name: Configure git credentials
+ uses: oleksiyrudenko/gha-git-credentials@v2
+ with:
+ global: true
+ name: "Gitea-Actions Bot"
+ email: "gitea-actions@ednz.fr"
+ actor: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_USERNAME }}
+ token: ${{ steps.import-secrets.outputs.GITEA_ACTIONS_TOKEN }}
+
+ - name: Do release
+ run: cz -nr 21 bump --yes
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
+
+ - name: Push release
+ run: git push && git push --tags
+ shell: bash
+ working-directory: ${{ gitea.workspace }}
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0cd8e68
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,38 @@
+# Local .terraform directories
+**/.terraform/*
+
+# .tfstate files
+*.tfstate
+*.tfstate.*
+
+# Crash log files
+crash.log
+
+# Exclude all .tfvars files, which are likely to contain sentitive data, such as
+# password, private keys, and other secrets. These should not be part of version
+# control as they are data points which are potentially sensitive and subject
+# to change depending on the environment.
+#
+#*.tfvars
+
+# Ignore override files as they are usually used to override resources locally and so
+# are not checked in
+override.tf
+override.tf.json
+*_override.tf
+*_override.tf.json
+
+# Include override files you do wish to add to version control using negated pattern
+#
+# !example_override.tf
+
+# Ignore CLI configuration files
+.terraformrc
+terraform.rc
+
+# Credentials files
+credentials.auto.tfvars
+
+# Local plan files
+plan.out
+**temp.txt
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c54adef..d4ea4c4 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,19 +1,28 @@
repos:
- - repo: https://github.com/antonbabenko/pre-commit-terraform
- rev: v1.86.0
+ - repo: https://github.com/tofuutils/pre-commit-opentofu
+ rev: v2.0.0
hooks:
- - id: terraform_fmt
- - id: terraform_docs
+ - id: tofu_fmt
+ - id: tofu_docs
args:
- "--hook-config=--path-to-file=README.md"
- "--hook-config=--add-to-existing-file=true"
- "--hook-config=--create-file-if-not-exist=true"
+ - "--hook-config=--use-standard-markers=true"
- "--args=--escape=false"
- "--args=--lockfile=false"
- "--args=--indent 3"
- "--args=--show all"
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.5.0
+ rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
+ - repo: https://github.com/commitizen-tools/commitizen
+ rev: v3.29.1
+ hooks:
+ - id: commitizen
+ - id: commitizen-branch
+ stages:
+ - post-commit
+ - push
diff --git a/.terraform.lock.hcl b/.terraform.lock.hcl
new file mode 100644
index 0000000..59aa238
--- /dev/null
+++ b/.terraform.lock.hcl
@@ -0,0 +1,41 @@
+# This file is maintained automatically by "tofu init".
+# Manual edits may be lost in future updates.
+
+provider "registry.opentofu.org/hashicorp/vault" {
+ version = "4.4.0"
+ hashes = [
+ "h1:s0t6P9ZfUQnHLxtUcnpPWpME68KwO/OxZqHAKSIvOoo=",
+ "zh:0309ea8f81386e17ab13c06c5991ca959708c55c815b0cfba2bbcd865e0d606e",
+ "zh:40e56199ccd266bffa216e8ebbcdc2e29b6ef5145b39377be766e763cac759c8",
+ "zh:6fad1f073bd2e53e34736e000f98db581137e153ac80bbb5c4f1a1e38b46a1d2",
+ "zh:74564fd4759decccf7f3c952aa2feba1012f103a66ec354aa3b3292a2f1b2412",
+ "zh:7aae012c1a43e6e5dae6f608ec0f08cdb3f95fa121a32e413fe7ee37cb99947f",
+ "zh:7c83f508e164844b1dd9bafe9de0fe60c7be7b55a02e704a6e2f50cff38b7d96",
+ "zh:873a42322b68d9fba4a38217b97ee04a1eb617e811d7f9954016f5c3eb6cb0bc",
+ "zh:9db2b13472cf91a5f18f0a7c6ae532277c05b0980d87f492341426b981679f7b",
+ "zh:ac1cbd2926265db80efe3f1814bed82901f7d8a7d4e5b1e22592e1eef234b1c7",
+ "zh:f465a955cc96f640e7426a648ba672c169a4a2959bad6146fe61583d67642561",
+ ]
+}
+
+provider "registry.opentofu.org/terraform-provider-openstack/openstack" {
+ version = "2.1.0"
+ constraints = ">= 1.54.0, ~> 2.1.0"
+ hashes = [
+ "h1:2TcmfEzBOGQPALErrXTaL6v+k/WAL40adao4izRYmdw=",
+ "zh:113661750398bf21c8fe36aade9fb6f5eb82b5bcd3bcd30bd37ac805d83398f4",
+ "zh:1b3c26347b9cd61e413ee93c2f422cc3278a77f55fd3516eaabb3e2a85f65281",
+ "zh:1b751bbf1e4152829a643b532fd3f5967a2e89a41fac381257e0b41665be3306",
+ "zh:1b967bbfd9b344419c0e0df0c3a15fcbd731e91f19a18955a55aace8d9ec039a",
+ "zh:1bc0fc7c0a21e568db043b654501ce668ba19bf7628d37a7d2aaa512fd6e5aeb",
+ "zh:425cbf61757d4b503e7bf0f409ea59835ca3afbd2432d56ad552c2e5d234a572",
+ "zh:67d4f059cb4d73bf6c060313ec32962c4e5bd8dc7be2542a6f2098ab32575cd9",
+ "zh:7fe841ac5b68a4f52fb3cf45070828f3845de44746679d434e4349f3c23e3ef2",
+ "zh:ac1ed4c6ef0b6a3410568a05d3f9933d184497f065988503c43da0b2f0786ab2",
+ "zh:c5c0d14c86fabd9ab6a5d555e6a8d511942665fb5fa948dd452b0d1934068344",
+ "zh:c9ae5c210192275185d6823566a9421983e8e64c2665a4cae00b92dd0706bd19",
+ "zh:ee9865ccc053e7f345e532654fb628d1cf1e81cd2e929643c1691bebffcf7b98",
+ "zh:f3416d2f666095e740522c4964e436470bb9ec17bd53aaae8169ad93297d07bd",
+ "zh:fbca85457dd49e17168989d64f7cfc4a519d55ef4e00e89cea2859e87ad87f83",
+ ]
+}
diff --git a/LICENSE b/LICENSE
index 475d657..f412dc0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2017 Bertrand Lanson
+Copyright (c) 2023 Bertrand Lanson
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
diff --git a/README.md b/README.md
index d3faa78..b269d4c 100644
--- a/README.md
+++ b/README.md
@@ -45,3 +45,51 @@ No modules.
| [id](#output_id) | The id of the security group |
| [name](#output_name) | The name of the security group |
+
+### Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement_terraform) | >= 1.0.0 |
+| [openstack](#requirement_openstack) | >= 1.54 |
+
+### Providers
+
+| Name | Version |
+|------|---------|
+| [openstack](#provider_openstack) | >= 1.54 |
+
+### Modules
+
+No modules.
+
+### Resources
+
+| Name | Type |
+|------|------|
+| [openstack_networking_secgroup_rule_v2.egress](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
+| [openstack_networking_secgroup_rule_v2.ingress](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_rule_v2) | resource |
+| [openstack_networking_secgroup_v2.this](https://registry.terraform.io/providers/terraform-provider-openstack/openstack/latest/docs/resources/networking_secgroup_v2) | resource |
+
+### Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [delete_default_rules](#input_delete_default_rules) | Whether or not to delete the default egress rules applied to the security group.
Default rules allow egress ipv4 and ipv6 to 0.0.0.0/0. | `bool` | `false` | no |
+| [description](#input_description) | Description for the security group. | `string` | `null` | no |
+| [egress_rules](#input_egress_rules) | The list of egress rules to attach to the security group.
You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
provided by the openstack provider, except region, which defaults to the region of the provider used,
and direction, which defaults to egress.
By default, if ethertype is not specified, it will by IPv4. | `map(map(string))` | `{}` | no |
+| [ingress_rules](#input_ingress_rules) | The list of ingress rules to attach to the security group.
You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
provided by the openstack provider, except region, which defaults to the region of the provider used,
and direction, which defaults to ingress.
By default, if ethertype is not specified, it will by IPv4. | `map(map(string))` | `{}` | no |
+| [name](#input_name) | The name of the security group. | `string` | n/a | yes |
+| [tags](#input_tags) | A list of tags (strings) to apply to the security group | `list(string)` | `[]` | no |
+| [tenant_id](#input_tenant_id) | The tenant for which to create the security group.
This is only required for admins creating security groups for other tenant. | `string` | `null` | no |
+
+### Outputs
+
+| Name | Description |
+|------|-------------|
+| [id](#output_id) | The id of the security group |
+| [name](#output_name) | The name of the security group |
+| [sg_egress_rules_raw](#output_sg_egress_rules_raw) | The raw security group egress rules, if any (except the default ones, if created) |
+| [sg_ingress_rules_raw](#output_sg_ingress_rules_raw) | The raw security group ingress rules, if any |
+| [sg_raw](#output_sg_raw) | The raw security group object, with all its values |
+
diff --git a/examples/.gitkeep b/examples/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/modules/.gitkeep b/modules/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/outputs.tf b/outputs.tf
index f9aab26..4653a95 100644
--- a/outputs.tf
+++ b/outputs.tf
@@ -1,9 +1,34 @@
output "name" {
value = openstack_networking_secgroup_v2.this.name
+ sensitive = false
description = "The name of the security group"
+ depends_on = []
}
output "id" {
value = openstack_networking_secgroup_v2.this.id
+ sensitive = false
description = "The id of the security group"
+ depends_on = []
+}
+
+output "sg_raw" {
+ value = openstack_networking_secgroup_v2.this
+ sensitive = false
+ description = "The raw security group object, with all its values"
+ depends_on = []
+}
+
+output "sg_ingress_rules_raw" {
+ value = length(openstack_networking_secgroup_rule_v2.ingress) > 0 ? openstack_networking_secgroup_rule_v2.ingress : null
+ sensitive = false
+ description = "The raw security group ingress rules, if any"
+ depends_on = []
+}
+
+output "sg_egress_rules_raw" {
+ value = length(openstack_networking_secgroup_rule_v2.egress) > 0 ? openstack_networking_secgroup_rule_v2.egress : null
+ sensitive = false
+ description = "The raw security group egress rules, if any (except the default ones, if created)"
+ depends_on = []
}
diff --git a/tests/complex.tftest.hcl b/tests/complex.tftest.hcl
new file mode 100644
index 0000000..7678cc1
--- /dev/null
+++ b/tests/complex.tftest.hcl
@@ -0,0 +1,87 @@
+run "complex" {
+ module {
+ source = "./tests/module"
+ }
+
+ variables {
+ name = "complex-sg"
+ description = "Tofu automated tests."
+ delete_default_rules = true
+ ingress_rules = {
+ http = {
+ protocol = "tcp"
+ port_range_min = 80
+ port_range_max = 80
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ https = {
+ protocol = "tcp"
+ port_range_min = 443
+ port_range_max = 443
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ cluster = {
+ protocol = ""
+ port_range_min = 0
+ port_range_max = 0
+ remote_group_id = "self"
+ }
+ ssh = {
+ protocol = "tcp"
+ port_range_min = 22
+ port_range_max = 22
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ }
+ egress_rules = {
+ icmp = {
+ protocol = "icmp"
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ }
+ tags = [
+ "tofu=true",
+ "env=testing",
+ ]
+ }
+
+ assert {
+ condition = module.security_group.name == "complex-sg"
+ error_message = "The security group name is not what was set as input"
+ }
+
+ assert {
+ condition = can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", module.security_group.id))
+ error_message = "The security group id is not a valid uuid"
+ }
+
+ assert {
+ condition = length(module.security_group.sg_ingress_rules_raw) == 4
+ error_message = "There are not the expected amount of ingress rules"
+ }
+
+ assert {
+ condition = length(module.security_group.sg_egress_rules_raw) == 1
+ error_message = "There are not the expected amount of egress rules"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["http"].remote_ip_prefix == "0.0.0.0/0"
+ error_message = "The http ingress rule is not scoped to the correct remote cidr"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["https"].remote_ip_prefix == "0.0.0.0/0"
+ error_message = "The https ingress rule is not scoped to the correct remote cidr"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["cluster"].remote_group_id == module.security_group.id
+ error_message = "The cluster ingress rule is not scoped to itself"
+ }
+
+ assert {
+ condition = module.security_group.sg_egress_rules_raw["icmp"].remote_ip_prefix == "0.0.0.0/0"
+ error_message = "The icmp egress rule is not scoped to the correct remote cidr"
+ }
+}
diff --git a/tests/module/.terraform.lock.hcl b/tests/module/.terraform.lock.hcl
new file mode 100644
index 0000000..59aa238
--- /dev/null
+++ b/tests/module/.terraform.lock.hcl
@@ -0,0 +1,41 @@
+# This file is maintained automatically by "tofu init".
+# Manual edits may be lost in future updates.
+
+provider "registry.opentofu.org/hashicorp/vault" {
+ version = "4.4.0"
+ hashes = [
+ "h1:s0t6P9ZfUQnHLxtUcnpPWpME68KwO/OxZqHAKSIvOoo=",
+ "zh:0309ea8f81386e17ab13c06c5991ca959708c55c815b0cfba2bbcd865e0d606e",
+ "zh:40e56199ccd266bffa216e8ebbcdc2e29b6ef5145b39377be766e763cac759c8",
+ "zh:6fad1f073bd2e53e34736e000f98db581137e153ac80bbb5c4f1a1e38b46a1d2",
+ "zh:74564fd4759decccf7f3c952aa2feba1012f103a66ec354aa3b3292a2f1b2412",
+ "zh:7aae012c1a43e6e5dae6f608ec0f08cdb3f95fa121a32e413fe7ee37cb99947f",
+ "zh:7c83f508e164844b1dd9bafe9de0fe60c7be7b55a02e704a6e2f50cff38b7d96",
+ "zh:873a42322b68d9fba4a38217b97ee04a1eb617e811d7f9954016f5c3eb6cb0bc",
+ "zh:9db2b13472cf91a5f18f0a7c6ae532277c05b0980d87f492341426b981679f7b",
+ "zh:ac1cbd2926265db80efe3f1814bed82901f7d8a7d4e5b1e22592e1eef234b1c7",
+ "zh:f465a955cc96f640e7426a648ba672c169a4a2959bad6146fe61583d67642561",
+ ]
+}
+
+provider "registry.opentofu.org/terraform-provider-openstack/openstack" {
+ version = "2.1.0"
+ constraints = ">= 1.54.0, ~> 2.1.0"
+ hashes = [
+ "h1:2TcmfEzBOGQPALErrXTaL6v+k/WAL40adao4izRYmdw=",
+ "zh:113661750398bf21c8fe36aade9fb6f5eb82b5bcd3bcd30bd37ac805d83398f4",
+ "zh:1b3c26347b9cd61e413ee93c2f422cc3278a77f55fd3516eaabb3e2a85f65281",
+ "zh:1b751bbf1e4152829a643b532fd3f5967a2e89a41fac381257e0b41665be3306",
+ "zh:1b967bbfd9b344419c0e0df0c3a15fcbd731e91f19a18955a55aace8d9ec039a",
+ "zh:1bc0fc7c0a21e568db043b654501ce668ba19bf7628d37a7d2aaa512fd6e5aeb",
+ "zh:425cbf61757d4b503e7bf0f409ea59835ca3afbd2432d56ad552c2e5d234a572",
+ "zh:67d4f059cb4d73bf6c060313ec32962c4e5bd8dc7be2542a6f2098ab32575cd9",
+ "zh:7fe841ac5b68a4f52fb3cf45070828f3845de44746679d434e4349f3c23e3ef2",
+ "zh:ac1ed4c6ef0b6a3410568a05d3f9933d184497f065988503c43da0b2f0786ab2",
+ "zh:c5c0d14c86fabd9ab6a5d555e6a8d511942665fb5fa948dd452b0d1934068344",
+ "zh:c9ae5c210192275185d6823566a9421983e8e64c2665a4cae00b92dd0706bd19",
+ "zh:ee9865ccc053e7f345e532654fb628d1cf1e81cd2e929643c1691bebffcf7b98",
+ "zh:f3416d2f666095e740522c4964e436470bb9ec17bd53aaae8169ad93297d07bd",
+ "zh:fbca85457dd49e17168989d64f7cfc4a519d55ef4e00e89cea2859e87ad87f83",
+ ]
+}
diff --git a/tests/module/README.md b/tests/module/README.md
new file mode 100644
index 0000000..80d2df5
--- /dev/null
+++ b/tests/module/README.md
@@ -0,0 +1,46 @@
+# module
+
+
+### Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement_terraform) | >= 1.0.0 |
+| [openstack](#requirement_openstack) | ~> 2.1.0 |
+
+### Providers
+
+| Name | Version |
+|------|---------|
+| [vault](#provider_vault) | n/a |
+
+### Modules
+
+| Name | Source | Version |
+|------|--------|---------|
+| [security_group](#module_security_group) | ../../ | n/a |
+
+### Resources
+
+| Name | Type |
+|------|------|
+| [vault_kv_secret_v2.openstack_provider_project_info](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/data-sources/kv_secret_v2) | data source |
+| [vault_kv_secret_v2.openstack_provider_project_user](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/data-sources/kv_secret_v2) | data source |
+| [vault_kv_secret_v2.openstack_provider_region](https://registry.terraform.io/providers/hashicorp/vault/latest/docs/data-sources/kv_secret_v2) | data source |
+
+### Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [delete_default_rules](#input_delete_default_rules) | Whether or not to delete the default egress rules applied to the security group.
Default rules allow egress ipv4 and ipv6 to 0.0.0.0/0. | `bool` | `false` | no |
+| [description](#input_description) | Description for the security group. | `string` | `null` | no |
+| [egress_rules](#input_egress_rules) | The list of egress rules to attach to the security group.
You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
provided by the openstack provider, except region, which defaults to the region of the provider used,
and direction, which defaults to egress.
By default, if ethertype is not specified, it will by IPv4. | `map(map(string))` | `{}` | no |
+| [ingress_rules](#input_ingress_rules) | The list of ingress rules to attach to the security group.
You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
provided by the openstack provider, except region, which defaults to the region of the provider used,
and direction, which defaults to ingress.
By default, if ethertype is not specified, it will by IPv4. | `map(map(string))` | `{}` | no |
+| [name](#input_name) | The name of the security group. | `string` | n/a | yes |
+| [tags](#input_tags) | A list of tags (strings) to apply to the security group | `list(string)` | `[]` | no |
+| [tenant_id](#input_tenant_id) | The tenant for which to create the security group.
This is only required for admins creating security groups for other tenant. | `string` | `null` | no |
+
+### Outputs
+
+No outputs.
+
diff --git a/tests/module/locals.tf b/tests/module/locals.tf
new file mode 100644
index 0000000..cdeaf5f
--- /dev/null
+++ b/tests/module/locals.tf
@@ -0,0 +1,9 @@
+locals {
+ name = var.name
+ description = var.description
+ tenant_id = var.tenant_id
+ delete_default_rules = var.delete_default_rules
+ ingress_rules = var.ingress_rules
+ egress_rules = var.egress_rules
+ tags = var.tags
+}
diff --git a/tests/module/main.tf b/tests/module/main.tf
new file mode 100644
index 0000000..53419ec
--- /dev/null
+++ b/tests/module/main.tf
@@ -0,0 +1,52 @@
+terraform {
+ required_version = ">= 1.0.0"
+ required_providers {
+ vault = {
+ source = "hashicorp/vault"
+ }
+ openstack = {
+ source = "terraform-provider-openstack/openstack"
+ version = "~> 2.1.0"
+ }
+ }
+}
+
+provider "vault" {
+ address = "https://active.vault.service.consul:8200"
+ skip_tls_verify = true
+}
+
+provider "openstack" {
+ auth_url = data.vault_kv_secret_v2.openstack_provider_region.data["auth_url"]
+ region = data.vault_kv_secret_v2.openstack_provider_region.data["region_name"]
+ tenant_name = data.vault_kv_secret_v2.openstack_provider_project_info.data["tenant_name"]
+ application_credential_id = data.vault_kv_secret_v2.openstack_provider_project_user.data["application_credential_id"]
+ application_credential_secret = data.vault_kv_secret_v2.openstack_provider_project_user.data["application_credential_secret"]
+}
+
+data "vault_kv_secret_v2" "openstack_provider_region" {
+ mount = "kv"
+ name = "infrastructure/openstack/regions/dc3_a"
+}
+
+data "vault_kv_secret_v2" "openstack_provider_project_user" {
+ mount = "kv"
+ name = "infrastructure/openstack/projects/pcp_dawxdax/users/tofu"
+}
+
+data "vault_kv_secret_v2" "openstack_provider_project_info" {
+ mount = "kv"
+ name = "infrastructure/openstack/projects/pcp_dawxdax/info"
+}
+
+module "security_group" {
+ source = "../../"
+
+ name = local.name
+ description = local.description
+ tenant_id = local.tenant_id
+ delete_default_rules = local.delete_default_rules
+ ingress_rules = local.ingress_rules
+ egress_rules = local.egress_rules
+ tags = local.tags
+}
diff --git a/tests/module/variables.tf b/tests/module/variables.tf
new file mode 100644
index 0000000..22f087f
--- /dev/null
+++ b/tests/module/variables.tf
@@ -0,0 +1,58 @@
+variable "name" {
+ type = string
+ description = "The name of the security group."
+}
+
+variable "description" {
+ type = string
+ description = "Description for the security group."
+ default = null
+}
+
+variable "tenant_id" {
+ type = string
+ description = <<-EOT
+ The tenant for which to create the security group.
+ This is only required for admins creating security groups for other tenant.
+ EOT
+ default = null
+}
+
+variable "delete_default_rules" {
+ type = bool
+ description = <<-EOT
+ Whether or not to delete the default egress rules applied to the security group.
+ Default rules allow egress ipv4 and ipv6 to 0.0.0.0/0.
+ EOT
+ default = false
+}
+
+variable "ingress_rules" {
+ type = map(map(string))
+ description = <<-EOT
+ The list of ingress rules to attach to the security group.
+ You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
+ provided by the openstack provider, except region, which defaults to the region of the provider used,
+ and direction, which defaults to ingress.
+ By default, if ethertype is not specified, it will by IPv4.
+ EOT
+ default = {}
+}
+
+variable "egress_rules" {
+ type = map(map(string))
+ description = <<-EOT
+ The list of egress rules to attach to the security group.
+ You can use all regular entries from the openstack_networking_secgroup_rule_v2 resource
+ provided by the openstack provider, except region, which defaults to the region of the provider used,
+ and direction, which defaults to egress.
+ By default, if ethertype is not specified, it will by IPv4.
+ EOT
+ default = {}
+}
+
+variable "tags" {
+ type = list(string)
+ description = "A list of tags (strings) to apply to the security group"
+ default = []
+}
diff --git a/tests/self.tftest.hcl b/tests/self.tftest.hcl
new file mode 100644
index 0000000..0891564
--- /dev/null
+++ b/tests/self.tftest.hcl
@@ -0,0 +1,56 @@
+run "self" {
+ module {
+ source = "./tests/module"
+ }
+
+ variables {
+ name = "self-sg"
+ description = "Tofu automated tests."
+ delete_default_rules = false
+ ingress_rules = {
+ cluster = {
+ protocol = ""
+ port_range_min = 0
+ port_range_max = 0
+ remote_group_id = "self"
+ }
+ }
+ egress_rules = {
+ cluster = {
+ protocol = ""
+ port_range_min = 0
+ port_range_max = 0
+ remote_group_id = "self"
+ }
+ }
+ tags = [
+ "tofu=true",
+ "env=testing",
+ ]
+ }
+
+ assert {
+ condition = module.security_group.name == "self-sg"
+ error_message = "The security group name is not what was set as input"
+ }
+
+ assert {
+ condition = can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", module.security_group.id))
+ error_message = "The security group id is not a valid uuid"
+ }
+
+ assert {
+ condition = length(module.security_group.sg_ingress_rules_raw) == 1
+ error_message = "There are not the expected amount of ingress rules"
+ }
+
+ assert {
+ condition = length(module.security_group.sg_egress_rules_raw) == 1
+ error_message = "There are not the expected amount of egress rules"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["cluster"].remote_group_id == module.security_group.id
+ error_message = "The cluster ingress rule is not scoped to itself"
+ }
+}
diff --git a/tests/simple.tftest.hcl b/tests/simple.tftest.hcl
new file mode 100644
index 0000000..fc0861c
--- /dev/null
+++ b/tests/simple.tftest.hcl
@@ -0,0 +1,55 @@
+run "simple" {
+ module {
+ source = "./tests/module"
+ }
+
+ variables {
+ name = "simple-sg"
+ description = "Tofu automated tests."
+ delete_default_rules = false
+ ingress_rules = {
+ http = {
+ protocol = "tcp"
+ port_range_min = 80
+ port_range_max = 80
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ https = {
+ protocol = "tcp"
+ port_range_min = 443
+ port_range_max = 443
+ remote_ip_prefix = "0.0.0.0/0"
+ }
+ }
+ egress_rules = {}
+ tags = [
+ "tofu=true",
+ "env=testing",
+ ]
+ }
+
+ assert {
+ condition = module.security_group.name == "simple-sg"
+ error_message = "The security group name is not what was set as input"
+ }
+
+ assert {
+ condition = can(regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$", module.security_group.id))
+ error_message = "The security group id is not a valid uuid"
+ }
+
+ assert {
+ condition = length(module.security_group.sg_ingress_rules_raw) == 2
+ error_message = "There are not the expected amount of ingress rules"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["http"].remote_ip_prefix == "0.0.0.0/0"
+ error_message = "The http ingress rule is not scoped to the correct remote cidr"
+ }
+
+ assert {
+ condition = module.security_group.sg_ingress_rules_raw["https"].remote_ip_prefix == "0.0.0.0/0"
+ error_message = "The https ingress rule is not scoped to the correct remote cidr"
+ }
+}