Skip to content

Testing and Validation

Chris Panagiotidis edited this page Jun 13, 2026 · 3 revisions

Testing And Validation

The project uses Terraform validation, security scans, OPA policy checks, and Terratest-style integration tests.

Testing and validation flow

Sources:

Validation Layers

Layer Tool Purpose Where it runs
Format terraform fmt Consistent Terraform formatting Local and CI
Static validation terraform validate Valid Terraform syntax and provider graph Local and CI
Security scan tfsec Terraform security checks CI
Security scan Checkov Terraform security and compliance checks CI
Secret scan Gitleaks Prevent committed secrets CI
Policy as code OPA/Rego Enforce project-specific guardrails CI
Lint TFLint Terraform lint and provider rules CI advisory
Cost Infracost Cost estimate CI advisory
Integration Terratest Verify deployed Azure resources Optional/local or custom action

Local Validation Commands

Safe commands that do not deploy:

terraform fmt -check -recursive -diff
terraform init -backend=false
terraform validate -no-color

Optional local plan:

terraform init -backend=false
terraform plan -var-file=environments/cheap-lab.tfvars

For remote-state plans, configure backend carefully and avoid committing backend config files.

Expected Local Output

Use these as rough pass indicators. Exact provider versions and timings can differ.

terraform fmt -check -recursive -diff
# no output means formatting is clean
terraform validate -no-color
Success! The configuration is valid.

If a command writes .terraform, lock files, or plan artifacts locally, do not commit generated files unless they are intentionally tracked by the repository.

Plan JSON Validation

Plan JSON is useful for regression checks:

terraform plan -var-file=environments/cheap-lab.tfvars -out=tfplan
terraform show -json tfplan > tfplan.json

High-value checks:

Check Expected result
Public RDP No broad 0.0.0.0/0 RDP path
LB RDP NAT No RDP NAT rules by default
SQL Public network access disabled when SQL is enabled
Key Vault Network ACLs align with private-first intent
Storage Public blob access disabled
Diagnostics Deployed important resources have diagnostic settings
Tags Required tags exist

Terratest Suite

Test source: tests/landing_zone_test.go

Current tests:

Test What it checks
TestLandingZoneDeployment/HubVNetExists Hub VNet exists
TestLandingZoneDeployment/IdentityVNetExists Identity VNet exists
TestLandingZoneDeployment/VNetPeeringConfigured Hub VNet has peerings
TestKeyVaultAccessible/KeyVaultExists Key Vault exists in shared services resource group
TestNetworkSecurityGroups/ManagementNSGExists Jumpbox NSG exists
TestResourceTags/ResourceGroupHasTags Hub resource group has required tags

Terratest Environment Variables

The tests use:

Variable Purpose Default
ARM_SUBSCRIPTION_ID Azure subscription to query Required or tests skip
TEST_ENVIRONMENT Environment name used in resource naming lab
TEST_LOCATION_SHORT Location short code used in resource naming wus2

Example:

$env:ARM_SUBSCRIPTION_ID = "<subscription-id>"
$env:TEST_ENVIRONMENT = "cheap-lab"
$env:TEST_LOCATION_SHORT = "wus2"
Set-Location tests
go test ./... -v

If Go is not installed, install Go before running Terratest locally. The CI can run Terratest through .github/actions/terratest once enabled in workflow.

OPA Policy Tests

Policy source:

OPA checks are run by .github/actions/policy-check.

Expected deny examples:

  • Resource without tags.
  • Storage account with public nested items access.
  • Resource in a non-approved region.
  • SQL server with public network access.
  • Key Vault create without soft delete.

Expected warning examples:

  • Public IP creation.
  • Broad inbound NSG rule.
  • Large VM SKU.
  • VM without encryption at host.

Manual Validation After Apply

Networking:

  • Hub VNet exists.
  • Spoke VNets exist for selected profile.
  • Hub-to-spoke peerings exist.
  • Route tables are associated.
  • Firewall routes are present when firewall is enabled.
  • App Gateway backend health is healthy when enabled.

Security:

  • No public RDP unless intentionally enabled.
  • Load Balancer RDP NAT rules are absent by default.
  • Key Vault, Storage, and SQL public access match intended posture.
  • Private Endpoint DNS resolves from spokes.

Monitoring:

  • Log Analytics workspace exists.
  • Diagnostics exist for deployed optional services.
  • Alerts are scoped to real resource IDs.
  • Flow logs are enabled only when intended.

Cost:

  • Budget exists when cost management is enabled.
  • Budget email recipients are real.
  • Expensive resources are only enabled intentionally.

Suggested Future Test Improvements

  • Add unit-style tests for profile variable combinations.
  • Add plan JSON tests for public RDP rejection.
  • Add plan JSON tests for SQL public network access.
  • Add tests for absence of LB RDP NAT by default.
  • Add tests for Private Endpoint resources when enabled.
  • Add tests for App Gateway backend pool input.
  • Add CI job to run Terratest only against explicitly deployed test environments.

Evidence Matrix

Requirement Evidence
Terraform syntax valid terraform validate output
Formatting clean terraform fmt -check -recursive -diff output
Security scans passed tfsec, Checkov, Gitleaks job results
Policy gates passed OPA policy-check job result
Cost reviewed Infracost output or manual cost review
Plan reviewed Plan add/change/destroy counts and resource diff
Deployment works Apply job success and resource inventory
Environment works Terratest and manual Azure checks

Scenario Test Matrix

Scenario Profile Validation focus
Cheapest deployable learning path cheap-lab No expensive edge services, no public RDP, core topology
Full lab build lab Firewall, App Gateway, shared services, governance, monitoring
Development workload dev Workload dev, AKS option, lower governance friction
Production-like review prod Policy, secondary DC, VPN/on-prem simulation, stronger validation

Validation Evidence Quality

Good evidence:

  • Includes the command or workflow run that produced it.
  • Includes the selected profile and commit SHA.
  • Shows pass/fail result, not just raw output.
  • Redacts subscription IDs, tenant IDs, public IPs, object IDs, and secrets.
  • Links back to the issue or Project item that required the validation.

Bad evidence:

  • Screenshots with secrets or full identifiers.
  • A statement that something was checked without output or screenshot.
  • A plan generated from a different commit than the apply.
  • A local-only result for a change that affects GitHub Actions or Azure RBAC.

Next page: Azure Portal Validation Evidence

Clone this wiki locally