Skip to content

Commit

Permalink
Added unit and deployment tests for the defender for cloud contact se…
Browse files Browse the repository at this point in the history
…tting
  • Loading branch information
felipebbc committed Feb 29, 2024
1 parent bd801cc commit 9a38335
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
variable "subscription_billing_scope" {
type = string
}

variable "subscription_alias_name" {
type = string
}

variable "subscription_display_name" {
type = string
}

variable "subscription_workload" {
type = string
}

variable "subscription_alias_enabled" {
type = bool
}

variable "subscription_use_azapi" {
type = bool
}

variable "subscription_dfc_contact_enabled" {
type = bool
}

variable "subscription_dfc_contact" {
type = object({
emails = optional(string, "")
phone = optional(string, "")
alert_notifications = optional(string, "Off")
notifications_by_role = optional(list(string), [])
})
}

module "subscription_test" {
source = "../../"
subscription_alias_name = var.subscription_alias_name
subscription_display_name = var.subscription_display_name
subscription_workload = var.subscription_workload
subscription_billing_scope = var.subscription_billing_scope
subscription_alias_enabled = var.subscription_alias_enabled
subscription_use_azapi = var.subscription_use_azapi
subscription_dfc_contact_enabled = var.subscription_dfc_contact_enabled
subscription_dfc_contact = var.subscription_dfc_contact
}

output "subscription_id" {
value = module.subscription_test.subscription_id
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
terraform {
required_version = ">= 1.3.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.7.0"
}
azapi = {
source = "Azure/azapi"
version = ">= 1.0.0"
}
}
}
54 changes: 52 additions & 2 deletions tests/subscription/subscriptionDeploy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func TestDeploySubscriptionAliasValid(t *testing.T) {
require.NoErrorf(t, err, "subscription id %s is not a valid uuid", sid)
}

// TestDeploySubscriptionAliasValid tests the deployment of a subscription alias
// TestDeploySubscriptionAliasValidAzApi tests the deployment of a subscription alias
// with valid input variables.
// We also test RP registration here.
// This test uses the azapi provider.
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestDeploySubscriptionAliasManagementGroupValid(t *testing.T) {
assert.NoErrorf(t, err, "subscription %s is not in management group %s", sid, v["subscription_management_group_id"].(string))
}

// TestDeploySubscriptionAliasManagementGroupValid tests the deployment of a subscription alias
// TestDeploySubscriptionAliasManagementGroupValidAzApi tests the deployment of a subscription alias
// with valid input variables.
func TestDeploySubscriptionAliasManagementGroupValidAzApi(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -192,6 +192,56 @@ func TestDeploySubscriptionAliasManagementGroupValidAzApi(t *testing.T) {
}
}

// TestDeploySubscriptionAliasDfcContactValid tests the deployment of a subscription alias
// with valid Defender for Cloud contact settings variables.
func TestDeploySubscriptionAliasDfcContactValid(t *testing.T) {
t.Parallel()
utils.PreCheckDeployTests(t)

v, err := getValidInputVariables(billingScope)
require.NoError(t, err)
v["subscription_billing_scope"] = billingScope
v["subscription_dfc_contact_enabled"] = true
v["subscription_dfc_contact"] = map[string]any{
"emails": "[email protected]",
"phone": "+555-555-5555",
"alert_notifications": "High",
"notifications_by_role": []string{"Owner"},
}

testDir := filepath.Join("testdata", t.Name())
test, err := setuptest.Dirs(moduleDir, testDir).WithVars(v).InitPlanShowWithPrepFunc(t, utils.AzureRmAndRequiredProviders)
require.NoError(t, err)
defer test.Cleanup()
require.NoError(t, err)

// Defer the cleanup of the subscription alias to the end of the test.
// Should be run after the Terraform destroy.
// We don't know the sub ID yet, so use zeros for now and then
// update it after the apply.
u := uuid.MustParse("00000000-0000-0000-0000-000000000000")
defer func() {
err := azureutils.CancelSubscription(t, &u)
if err != nil {
t.Logf("cannot cancel subscription: %v", err)
}
}()

// defer terraform destroy, but wrap in a try.Do to retry a few times
// due to eventual consistency of the subscription aliases API
defer test.DestroyRetry(setuptest.DefaultRetry) //nolint:errcheck
test.ApplyIdempotent().ErrorIsNil(t)

sid, err := terraform.OutputE(t, test.Options, "subscription_id")
assert.NoError(t, err)

u, err = uuid.Parse(sid)
assert.NoErrorf(t, err, "subscription id %s is not a valid uuid", sid)

err = azureutils.IsSubscriptionInManagementGroup(t, u, v["subscription_management_group_id"].(string))
assert.NoErrorf(t, err, "subscription %s is not in management group %s", sid, v["subscription_management_group_id"].(string))
}

// getValidInputVariables returns a set of valid input variables that can be used and modified for testing scenarios.
func getValidInputVariables(billingScope string) (map[string]any, error) {
r, err := utils.RandomHex(4)
Expand Down
31 changes: 31 additions & 0 deletions tests/subscription/subscription_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,37 @@ func TestSubscriptionInvalidTagName(t *testing.T) {
assert.Contains(t, utils.SanitiseErrorMessage(err), "Tag name must contain neither `<>%&\\?/` nor control characters, and must be between 0-512 characters.")
}

// TestSubscriptionAliasCreateValidWithDfcContact tests the
// validation functions with valid data, including a Defender for Cloud contact,
// then creates a plan and compares the input variables to the planned values.
func TestSubscriptionAliasCreateValidWithDfcContact(t *testing.T) {
t.Parallel()

v := getMockInputVariables()
v["subscription_dfc_contact_enabled"] = true
v["subscription_dfc_contact"] = map[string]any{
"emails": "[email protected]",
"phone": "+555-555-5555",
"alert_notifications": "High",
"notifications_by_role": []string{"Owner"},
}

test, err := setuptest.Dirs(moduleDir, "").WithVars(v).InitPlanShowWithPrepFunc(t, utils.AzureRmAndRequiredProviders)
require.NoError(t, err)
defer test.Cleanup()

check.InPlan(test.PlanStruct).NumberOfResourcesEquals(2).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azurerm_subscription.this[0]").Key("alias").HasValue(v["subscription_alias_name"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azurerm_subscription.this[0]").Key("billing_scope_id").HasValue(v["subscription_billing_scope"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azurerm_subscription.this[0]").Key("subscription_name").HasValue(v["subscription_display_name"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azurerm_subscription.this[0]").Key("workload").HasValue(v["subscription_workload"]).ErrorIsNil(t)

check.InPlan(test.PlanStruct).That("azapi_resource.subscription_dfc_contact[0]").Key("body").Query("properties.emails").HasValue(v["subscription_dfc_contact"].(map[string]any)["emails"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azapi_resource.subscription_dfc_contact[0]").Key("body").Query("properties.phone").HasValue(v["subscription_dfc_contact"].(map[string]any)["phone"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azapi_resource.subscription_dfc_contact[0]").Key("body").Query("properties.alertNotifications.minimalSeverity").HasValue(v["subscription_dfc_contact"].(map[string]any)["alert_notifications"]).ErrorIsNil(t)
check.InPlan(test.PlanStruct).That("azapi_resource.subscription_dfc_contact[0]").Key("body").Query("properties.notificationsByRole.roles.0").HasValue(v["subscription_dfc_contact"].(map[string]any)["notifications_by_role"].([]string)[0]).ErrorIsNil(t)
}

// getMockInputVariables returns a set of mock input variables that can be used and modified for testing scenarios.
func getMockInputVariables() map[string]any {
return map[string]any{
Expand Down

0 comments on commit 9a38335

Please sign in to comment.