From a9b6b334192159255bd61f2f1380785839b84d95 Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Thu, 2 Jul 2026 20:21:50 +0200 Subject: [PATCH 1/5] refactor: migrate starterkit building blocks to meshstack_building_block Migrate the app-team-managed child building blocks in the aks, azure-vm and ske starterkits from the deprecated meshstack_building_block_v2 to meshstack_building_block. - Convert per-type inputs (value_string/value_int/value_bool/...) to the unified value = jsonencode(...) shape; CODE inputs are double-encoded per the terraform runner contract (jsonencode(jsonencode({...}))). - Read status.outputs via jsondecode(...value). - Add moved{} blocks so the live blocks migrate in place (no destroy/recreate). - Bump the meshstack provider constraint to >= 0.23.0 and regenerate READMEs. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../aks/starterkit/buildingblock/README.md | 8 +-- modules/aks/starterkit/buildingblock/main.tf | 54 ++++++++++++------- .../aks/starterkit/buildingblock/outputs.tf | 12 ++--- .../aks/starterkit/buildingblock/versions.tf | 2 +- .../buildingblock/README.md | 4 +- .../buildingblock/main.tf | 25 +++++---- .../buildingblock/outputs.tf | 4 +- .../buildingblock/versions.tf | 2 +- .../ske-starterkit/buildingblock/README.md | 6 +-- .../ske/ske-starterkit/buildingblock/main.tf | 29 +++++++--- .../ske-starterkit/buildingblock/versions.tf | 2 +- 11 files changed, 93 insertions(+), 55 deletions(-) diff --git a/modules/aks/starterkit/buildingblock/README.md b/modules/aks/starterkit/buildingblock/README.md index f58f703b..b72ee7b3 100644 --- a/modules/aks/starterkit/buildingblock/README.md +++ b/modules/aks/starterkit/buildingblock/README.md @@ -15,7 +15,7 @@ This documentation is intended as a reference documentation for cloud foundation | Name | Version | |------|---------| -| [meshstack](#requirement\_meshstack) | >= 0.21.0 | +| [meshstack](#requirement\_meshstack) | >= 0.23.0 | ## Modules @@ -25,9 +25,9 @@ No modules. | Name | Type | |------|------| -| [meshstack_building_block_v2.github_actions_dev](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | -| [meshstack_building_block_v2.github_actions_prod](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | -| [meshstack_building_block_v2.repo](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | +| [meshstack_building_block.github_actions_dev](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | +| [meshstack_building_block.github_actions_prod](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | +| [meshstack_building_block.repo](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | | [meshstack_project.dev](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project) | resource | | [meshstack_project.prod](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project) | resource | | [meshstack_project_user_binding.creator_dev_admin](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project_user_binding) | resource | diff --git a/modules/aks/starterkit/buildingblock/main.tf b/modules/aks/starterkit/buildingblock/main.tf index 87a85ecc..90c81139 100644 --- a/modules/aks/starterkit/buildingblock/main.tf +++ b/modules/aks/starterkit/buildingblock/main.tf @@ -103,7 +103,7 @@ resource "meshstack_tenant_v4" "prod" { depends_on = [meshstack_project_user_binding.creator_prod_admin] } -resource "meshstack_building_block_v2" "repo" { +resource "meshstack_building_block" "repo" { spec = { building_block_definition_version_ref = { uuid = var.github_repo_definition_version_uuid @@ -117,31 +117,31 @@ resource "meshstack_building_block_v2" "repo" { inputs = { repo_name = { - value_string = local.repo_name + value = jsonencode(local.repo_name) } archive_repo_on_destroy = { - value_bool = var.archive_repo_on_destroy + value = jsonencode(var.archive_repo_on_destroy) } repo_owner = { - value_string = var.repo_admin != null ? var.repo_admin : "null" + value = jsonencode(var.repo_admin != null ? var.repo_admin : "null") } repo_visibility = { - value_string = var.github_repo_input_repo_visibility != null ? var.github_repo_input_repo_visibility : "private" + value = jsonencode(var.github_repo_input_repo_visibility != null ? var.github_repo_input_repo_visibility : "private") } use_template = { - value_bool = true + value = jsonencode(true) } template_owner = { - value_string = split("/", var.github_template_repo_path)[0] + value = jsonencode(split("/", var.github_template_repo_path)[0]) } template_repo = { - value_string = split("/", var.github_template_repo_path)[1] + value = jsonencode(split("/", var.github_template_repo_path)[1]) } } } } -resource "meshstack_building_block_v2" "github_actions_dev" { +resource "meshstack_building_block" "github_actions_dev" { spec = { building_block_definition_version_ref = { uuid = var.github_actions_connector_definition_version_uuid @@ -152,24 +152,24 @@ resource "meshstack_building_block_v2" "github_actions_dev" { } display_name = "GHA Connector Dev" parent_building_blocks = [{ - buildingblock_uuid = meshstack_building_block_v2.repo.metadata.uuid + buildingblock_uuid = meshstack_building_block.repo.metadata.uuid definition_uuid = var.github_repo_definition_uuid }] inputs = { github_environment_name = { - value_string = "development" + value = jsonencode("development") } additional_environment_variables = { - value_code = jsonencode({ + value = jsonencode(jsonencode({ "DOMAIN_NAME" = "${local.identifier}-dev" "AKS_NAMESPACE_NAME" = meshstack_tenant_v4.dev.spec.platform_tenant_id - }) + })) } } } } -resource "meshstack_building_block_v2" "github_actions_prod" { +resource "meshstack_building_block" "github_actions_prod" { spec = { display_name = "GHA Connector Prod" building_block_definition_version_ref = { @@ -180,19 +180,37 @@ resource "meshstack_building_block_v2" "github_actions_prod" { uuid = meshstack_tenant_v4.prod.metadata.uuid } parent_building_blocks = [{ - buildingblock_uuid = meshstack_building_block_v2.repo.metadata.uuid + buildingblock_uuid = meshstack_building_block.repo.metadata.uuid definition_uuid = var.github_repo_definition_uuid }] inputs = { github_environment_name = { - value_string = "production" + value = jsonencode("production") } additional_environment_variables = { - value_code = jsonencode({ + value = jsonencode(jsonencode({ "DOMAIN_NAME" = local.identifier "AKS_NAMESPACE_NAME" = meshstack_tenant_v4.prod.spec.platform_tenant_id - }) + })) } } } } + +# Migrate the app-team-managed child building blocks from the deprecated +# meshstack_building_block_v2 resource to meshstack_building_block in place — +# no destroy/recreate of the live blocks. +moved { + from = meshstack_building_block_v2.repo + to = meshstack_building_block.repo +} + +moved { + from = meshstack_building_block_v2.github_actions_dev + to = meshstack_building_block.github_actions_dev +} + +moved { + from = meshstack_building_block_v2.github_actions_prod + to = meshstack_building_block.github_actions_prod +} diff --git a/modules/aks/starterkit/buildingblock/outputs.tf b/modules/aks/starterkit/buildingblock/outputs.tf index c9aaa0fe..d96b1013 100644 --- a/modules/aks/starterkit/buildingblock/outputs.tf +++ b/modules/aks/starterkit/buildingblock/outputs.tf @@ -11,7 +11,7 @@ output "prod-link" { output "github_repo_url" { description = "URL of the created GitHub repository" - value = meshstack_building_block_v2.repo.status.outputs.repo_html_url.value_string + value = jsondecode(meshstack_building_block.repo.status.outputs.repo_html_url.value) } output "summary" { @@ -23,15 +23,15 @@ output "summary" { This starter kit has set up the following resources in workspace `${var.workspace_identifier}`: -@buildingblock[${meshstack_building_block_v2.repo.metadata.uuid}] +@buildingblock[${meshstack_building_block.repo.metadata.uuid}] @project[${meshstack_project.dev.metadata.owned_by_workspace}.${meshstack_project.dev.metadata.name}]\     @tenant[${meshstack_tenant_v4.dev.metadata.uuid}]\ -        @buildingblock[${meshstack_building_block_v2.github_actions_dev.metadata.uuid}] +        @buildingblock[${meshstack_building_block.github_actions_dev.metadata.uuid}] @project[${meshstack_project.prod.metadata.owned_by_workspace}.${meshstack_project.prod.metadata.name}]\     @tenant[${meshstack_tenant_v4.prod.metadata.uuid}]\ -        @buildingblock[${meshstack_building_block_v2.github_actions_prod.metadata.uuid}] +        @buildingblock[${meshstack_building_block.github_actions_prod.metadata.uuid}] --- @@ -52,7 +52,7 @@ Trigger a deployment by: - Pushing to the **main** branch (deploys to **dev**) - Merging **main** into **release** via PR (deploys to **prod**) -View deployment status: [GitHub Actions](${meshstack_building_block_v2.repo.status.outputs.repo_html_url.value_string}/actions/workflows/k8s-deploy.yml) +View deployment status: [GitHub Actions](${jsondecode(meshstack_building_block.repo.status.outputs.repo_html_url.value)}/actions/workflows/k8s-deploy.yml) - **Dev**: [${local.identifier}-dev.${var.apps_base_domain}](https://${local.identifier}-dev.${var.apps_base_domain}) - **Prod**: [${local.identifier}.${var.apps_base_domain}](https://${local.identifier}.${var.apps_base_domain}) @@ -66,7 +66,7 @@ View deployment status: [GitHub Actions](${meshstack_building_block_v2.repo.stat - Merge PR from **main → release** → deploys to **prod** ### 2. Monitor -- Check workflow status in the [Actions tab](<${meshstack_building_block_v2.repo.status.outputs.repo_html_url.value_string}/actions>) +- Check workflow status in the [Actions tab](<${jsondecode(meshstack_building_block.repo.status.outputs.repo_html_url.value)}/actions>) ### 3. Access AKS Namespaces - [Dev Namespace](/#/w/${var.workspace_identifier}/p/${meshstack_project.dev.metadata.name}/i/${meshstack_tenant_v4.dev.spec.platform_identifier}/overview/azure_kubernetes_service) diff --git a/modules/aks/starterkit/buildingblock/versions.tf b/modules/aks/starterkit/buildingblock/versions.tf index 82beb821..1b85386c 100644 --- a/modules/aks/starterkit/buildingblock/versions.tf +++ b/modules/aks/starterkit/buildingblock/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { meshstack = { source = "meshcloud/meshstack" - version = ">= 0.21.0" + version = ">= 0.23.0" } } } diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md b/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md index c4f29989..12c52cf7 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/README.md @@ -39,7 +39,7 @@ The Azure VM Starterkit building block automates the creation of a complete Azur | Name | Version | |------|---------| -| [meshstack](#requirement\_meshstack) | >= 0.9.0 | +| [meshstack](#requirement\_meshstack) | >= 0.23.0 | ## Modules @@ -49,7 +49,7 @@ No modules. | Name | Type | |------|------| -| [meshstack_building_block_v2.azure_vm](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | +| [meshstack_building_block.azure_vm](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | | [meshstack_project.vm_project](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project) | resource | | [meshstack_project_user_binding.creator_admin](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project_user_binding) | resource | | [meshstack_tenant_v4.vm_tenant](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/tenant_v4) | resource | diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf index 22ce1f7c..00517db0 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf @@ -51,7 +51,7 @@ resource "meshstack_tenant_v4" "vm_tenant" { } } -resource "meshstack_building_block_v2" "azure_vm" { +resource "meshstack_building_block" "azure_vm" { spec = { building_block_definition_version_ref = { uuid = var.azure_vm_definition_version_uuid @@ -63,29 +63,36 @@ resource "meshstack_building_block_v2" "azure_vm" { display_name = "Azure Virtual Machine" inputs = { vm_name = { - value_string = local.identifier + value = jsonencode(local.identifier) } location = { - value_string = var.vm_location + value = jsonencode(var.vm_location) } os_type = { - value_string = var.vm_os_type + value = jsonencode(var.vm_os_type) } vm_size = { - value_string = var.vm_size + value = jsonencode(var.vm_size) } admin_username = { - value_string = var.vm_admin_username + value = jsonencode(var.vm_admin_username) } enable_public_ip = { - value_bool = var.vm_enable_public_ip + value = jsonencode(var.vm_enable_public_ip) } ssh_public_key = { - value_string = var.vm_os_type == "Linux" ? var.vm_ssh_public_key : null + value = jsonencode(var.vm_os_type == "Linux" ? var.vm_ssh_public_key : null) } admin_password = { - value_string = var.vm_os_type == "Windows" ? var.vm_admin_password : null + value = jsonencode(var.vm_os_type == "Windows" ? var.vm_admin_password : null) } } } } + +# Migrate the child building block from the deprecated meshstack_building_block_v2 +# resource to meshstack_building_block in place. +moved { + from = meshstack_building_block_v2.azure_vm + to = meshstack_building_block.azure_vm +} diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf index 51ba70b3..354c6986 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/outputs.tf @@ -10,7 +10,7 @@ output "tenant_uuid" { output "vm_building_block_uuid" { description = "UUID of the Azure VM building block" - value = meshstack_building_block_v2.azure_vm.metadata.uuid + value = meshstack_building_block.azure_vm.metadata.uuid } output "summary" { @@ -24,7 +24,7 @@ This starter kit has set up the following resources in workspace `${var.workspac @project[${meshstack_project.vm_project.metadata.owned_by_workspace}.${meshstack_project.vm_project.metadata.name}]\     @tenant[${meshstack_tenant_v4.vm_tenant.metadata.uuid}]\ -        @buildingblock[${meshstack_building_block_v2.azure_vm.metadata.uuid}] +        @buildingblock[${meshstack_building_block.azure_vm.metadata.uuid}] --- diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/versions.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/versions.tf index e0c5393f..1b85386c 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/versions.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/versions.tf @@ -2,7 +2,7 @@ terraform { required_providers { meshstack = { source = "meshcloud/meshstack" - version = ">= 0.9.0" + version = ">= 0.23.0" } } } diff --git a/modules/ske/ske-starterkit/buildingblock/README.md b/modules/ske/ske-starterkit/buildingblock/README.md index 5c6173e7..4ee50f2b 100644 --- a/modules/ske/ske-starterkit/buildingblock/README.md +++ b/modules/ske/ske-starterkit/buildingblock/README.md @@ -14,7 +14,7 @@ This building block creates a dev and prod meshStack project pair, each with a d | Name | Version | |------|---------| -| [meshstack](#requirement\_meshstack) | >= 0.21.0 | +| [meshstack](#requirement\_meshstack) | >= 0.23.0 | | [random](#requirement\_random) | >= 3.8.1 | ## Modules @@ -25,8 +25,8 @@ No modules. | Name | Type | |------|------| -| [meshstack_building_block_v2.forgejo_connector](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | -| [meshstack_building_block_v2.git_repository](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block_v2) | resource | +| [meshstack_building_block.forgejo_connector](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | +| [meshstack_building_block.git_repository](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/building_block) | resource | | [meshstack_project.this](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project) | resource | | [meshstack_project_user_binding.creator_to_admin](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/project_user_binding) | resource | | [meshstack_tenant_v4.this](https://registry.terraform.io/providers/meshcloud/meshstack/latest/docs/resources/tenant_v4) | resource | diff --git a/modules/ske/ske-starterkit/buildingblock/main.tf b/modules/ske/ske-starterkit/buildingblock/main.tf index caa80caf..350bd352 100644 --- a/modules/ske/ske-starterkit/buildingblock/main.tf +++ b/modules/ske/ske-starterkit/buildingblock/main.tf @@ -20,7 +20,7 @@ locals { } } -resource "meshstack_building_block_v2" "git_repository" { +resource "meshstack_building_block" "git_repository" { spec = { building_block_definition_version_ref = var.building_block_definitions["git-repository"].version_ref # provisioned in backplane @@ -31,9 +31,9 @@ resource "meshstack_building_block_v2" "git_repository" { } inputs = { - name = { value_string = local.name } - description = { value_string = "Source code for application ${var.name}" } - clone_addr = { value_string = var.repo_clone_addr } + name = { value = jsonencode(local.name) } + description = { value = jsonencode("Source code for application ${var.name}") } + clone_addr = { value = jsonencode(var.repo_clone_addr) } } } wait_for_completion = true @@ -97,7 +97,7 @@ resource "meshstack_tenant_v4" "this" { depends_on = [meshstack_project_user_binding.creator_to_admin] } -resource "meshstack_building_block_v2" "forgejo_connector" { +resource "meshstack_building_block" "forgejo_connector" { for_each = meshstack_tenant_v4.this spec = { @@ -110,16 +110,29 @@ resource "meshstack_building_block_v2" "forgejo_connector" { } parent_building_blocks = [{ - buildingblock_uuid = meshstack_building_block_v2.git_repository.metadata.uuid + buildingblock_uuid = meshstack_building_block.git_repository.metadata.uuid definition_uuid = var.building_block_definitions["git-repository"].uuid }] inputs = { - stage = { value_string = each.key } - app_hostname = { value_string = local.app_hostnames[each.key] } + stage = { value = jsonencode(each.key) } + app_hostname = { value = jsonencode(local.app_hostnames[each.key]) } } } wait_for_completion = true } +# Migrate the app-team-managed child building blocks from the deprecated +# meshstack_building_block_v2 resource to meshstack_building_block in place — +# no destroy/recreate of the live blocks. +moved { + from = meshstack_building_block_v2.git_repository + to = meshstack_building_block.git_repository +} + +moved { + from = meshstack_building_block_v2.forgejo_connector + to = meshstack_building_block.forgejo_connector +} + diff --git a/modules/ske/ske-starterkit/buildingblock/versions.tf b/modules/ske/ske-starterkit/buildingblock/versions.tf index 03e4e989..95c07abe 100644 --- a/modules/ske/ske-starterkit/buildingblock/versions.tf +++ b/modules/ske/ske-starterkit/buildingblock/versions.tf @@ -3,7 +3,7 @@ terraform { required_providers { meshstack = { source = "meshcloud/meshstack" - version = ">= 0.21.0" + version = ">= 0.23.0" } random = { source = "hashicorp/random" From 3c3896014057ec408288edf9189d38df24d43db4 Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Thu, 2 Jul 2026 20:21:54 +0200 Subject: [PATCH 2/5] test: migrate e2e harnesses to meshstack_building_block MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch every e2e smoke-test building block from meshstack_building_block_v2 to meshstack_building_block, converting inputs to value = jsonencode(...) / sensitive blocks and rewriting the .tftest.hcl assertions to read outputs via jsondecode(...value) (CODE/JSON outputs decode twice). No moved{} blocks — e2e runs in ephemeral test state. Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/azure/budget-alert/e2e/main.tf | 8 ++--- .../tests/azure_budget_alert_hub.tftest.hcl | 8 ++--- modules/azure/resource-group/e2e/main.tf | 6 ++-- .../tests/azure_resource_group_hub.tftest.hcl | 12 +++---- modules/azure/storage-account/e2e/main.tf | 4 +-- .../azure_storage_account_hub.tftest.hcl | 16 ++++----- modules/meshstack/github-workflow/e2e/main.tf | 4 +-- .../meshstack_github_workflow_hub.tftest.hcl | 8 ++--- modules/meshstack/manual/e2e/main.tf | 10 +++--- .../building_block_manual_hub.tftest.hcl | 20 +++++------ modules/meshstack/noop/e2e/env-audit/main.tf | 2 +- modules/meshstack/noop/e2e/main.tf | 16 ++++----- modules/meshstack/noop/e2e/runner/main.tf | 16 ++++----- .../tests/building_block_noop_hub.tftest.hcl | 35 +++++++++---------- .../building_block_noop_runner_hub.tftest.hcl | 16 ++++----- .../noop/e2e/tests/env_audit_hub.tftest.hcl | 12 +++---- modules/ske/ske-starterkit/e2e/main.tf | 4 +-- ...ilding_block_ske_starterkit_hub.tftest.hcl | 12 +++---- modules/stackit/git-repository/e2e/main.tf | 10 +++--- ...lock_stackit_git-repository_hub.tftest.hcl | 12 +++---- modules/stackit/storage-bucket/e2e/main.tf | 4 +-- ...lock_stackit_storage-bucket_hub.tftest.hcl | 18 +++++----- 22 files changed, 126 insertions(+), 127 deletions(-) diff --git a/modules/azure/budget-alert/e2e/main.tf b/modules/azure/budget-alert/e2e/main.tf index cecd7c71..b01ac1b3 100644 --- a/modules/azure/budget-alert/e2e/main.tf +++ b/modules/azure/budget-alert/e2e/main.tf @@ -44,7 +44,7 @@ module "budget_alert" { backplane_name = "hub-e2e-budget-${var.test_context.name_suffix}" } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { depends_on = [module.budget_alert] wait_for_completion = true @@ -59,9 +59,9 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - contact_emails = { value_string = "e2e-test@example.com" } - monthly_budget_amount = { value_int = 1000 } - budget_name = { value_string = local.budget_name } + contact_emails = { value = jsonencode("e2e-test@example.com") } + monthly_budget_amount = { value = jsonencode(1000) } + budget_name = { value = jsonencode(local.budget_name) } } } } diff --git a/modules/azure/budget-alert/e2e/tests/azure_budget_alert_hub.tftest.hcl b/modules/azure/budget-alert/e2e/tests/azure_budget_alert_hub.tftest.hcl index 4d65e5f2..d0806909 100644 --- a/modules/azure/budget-alert/e2e/tests/azure_budget_alert_hub.tftest.hcl +++ b/modules/azure/budget-alert/e2e/tests/azure_budget_alert_hub.tftest.hcl @@ -1,11 +1,11 @@ run "azure_budget_alert_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "azure/budget-alert hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "azure/budget-alert hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["budget_amount"].value_int == 1000 - error_message = "expected budget_amount to be 1000, got ${meshstack_building_block_v2.this.status.outputs["budget_amount"].value_int}" + condition = jsondecode(meshstack_building_block.this.status.outputs["budget_amount"].value) == 1000 + error_message = "expected budget_amount to be 1000, got ${jsondecode(meshstack_building_block.this.status.outputs["budget_amount"].value)}" } } diff --git a/modules/azure/resource-group/e2e/main.tf b/modules/azure/resource-group/e2e/main.tf index d3b9f415..499ea987 100644 --- a/modules/azure/resource-group/e2e/main.tf +++ b/modules/azure/resource-group/e2e/main.tf @@ -46,7 +46,7 @@ module "resource_group" { backplane_name = "hub-e2e-rg-${var.test_context.name_suffix}" } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { depends_on = [module.resource_group] wait_for_completion = true @@ -61,8 +61,8 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - workspace_identifier = { value_string = var.test_context.workspace } - project_identifier = { value_string = local.project_identifier } + workspace_identifier = { value = jsonencode(var.test_context.workspace) } + project_identifier = { value = jsonencode(local.project_identifier) } } } } diff --git a/modules/azure/resource-group/e2e/tests/azure_resource_group_hub.tftest.hcl b/modules/azure/resource-group/e2e/tests/azure_resource_group_hub.tftest.hcl index ba4e98f8..9fcd586d 100644 --- a/modules/azure/resource-group/e2e/tests/azure_resource_group_hub.tftest.hcl +++ b/modules/azure/resource-group/e2e/tests/azure_resource_group_hub.tftest.hcl @@ -1,19 +1,19 @@ run "azure_resource_group_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "azure/resource-group hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "azure/resource-group hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = startswith(meshstack_building_block_v2.this.status.outputs["resource_group_name"].value_string, "rg-") - error_message = "expected resource_group_name to start with 'rg-', got ${meshstack_building_block_v2.this.status.outputs["resource_group_name"].value_string}" + condition = startswith(jsondecode(meshstack_building_block.this.status.outputs["resource_group_name"].value), "rg-") + error_message = "expected resource_group_name to start with 'rg-', got ${jsondecode(meshstack_building_block.this.status.outputs["resource_group_name"].value)}" } assert { condition = can(regex( "^/subscriptions/[^/]+/resourceGroups/rg-", - meshstack_building_block_v2.this.status.outputs["resource_group_id"].value_string + jsondecode(meshstack_building_block.this.status.outputs["resource_group_id"].value) )) - error_message = "expected resource_group_id to be a valid Azure Resource Group resource ID starting with /subscriptions/.../resourceGroups/rg-, got ${meshstack_building_block_v2.this.status.outputs["resource_group_id"].value_string}" + error_message = "expected resource_group_id to be a valid Azure Resource Group resource ID starting with /subscriptions/.../resourceGroups/rg-, got ${jsondecode(meshstack_building_block.this.status.outputs["resource_group_id"].value)}" } } diff --git a/modules/azure/storage-account/e2e/main.tf b/modules/azure/storage-account/e2e/main.tf index edb5ab17..2127cdf0 100644 --- a/modules/azure/storage-account/e2e/main.tf +++ b/modules/azure/storage-account/e2e/main.tf @@ -45,7 +45,7 @@ module "storage_account" { backplane_name = "hub-e2e-stg-${var.test_context.name_suffix}" } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { # depend on the entire backplane to force correct resource ordering at the module boundary,not just individual resources in the backplane depends_on = [module.storage_account] @@ -61,7 +61,7 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - storage_account_name = { value_string = local.storage_account_name_prefix } + storage_account_name = { value = jsonencode(local.storage_account_name_prefix) } } } } diff --git a/modules/azure/storage-account/e2e/tests/azure_storage_account_hub.tftest.hcl b/modules/azure/storage-account/e2e/tests/azure_storage_account_hub.tftest.hcl index 08ae12d5..a890952f 100644 --- a/modules/azure/storage-account/e2e/tests/azure_storage_account_hub.tftest.hcl +++ b/modules/azure/storage-account/e2e/tests/azure_storage_account_hub.tftest.hcl @@ -1,24 +1,24 @@ run "azure_storage_account_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "azure/storage-account hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "azure/storage-account hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { condition = can(regex( "^/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft\\.Storage/storageAccounts/", - meshstack_building_block_v2.this.status.outputs["storage_account_id"].value_string + jsondecode(meshstack_building_block.this.status.outputs["storage_account_id"].value) )) - error_message = "expected storage_account_id to be a valid Azure Storage Account resource ID, got ${meshstack_building_block_v2.this.status.outputs["storage_account_id"].value_string}" + error_message = "expected storage_account_id to be a valid Azure Storage Account resource ID, got ${jsondecode(meshstack_building_block.this.status.outputs["storage_account_id"].value)}" } assert { - condition = startswith(meshstack_building_block_v2.this.status.outputs["storage_account_name"].value_string, "st") - error_message = "expected storage_account_name to start with 'st', got ${meshstack_building_block_v2.this.status.outputs["storage_account_name"].value_string}" + condition = startswith(jsondecode(meshstack_building_block.this.status.outputs["storage_account_name"].value), "st") + error_message = "expected storage_account_name to start with 'st', got ${jsondecode(meshstack_building_block.this.status.outputs["storage_account_name"].value)}" } assert { - condition = startswith(meshstack_building_block_v2.this.status.outputs["storage_account_resource_group"].value_string, "rg-st") - error_message = "expected storage_account_resource_group to start with 'rg-st', got ${meshstack_building_block_v2.this.status.outputs["storage_account_resource_group"].value_string}" + condition = startswith(jsondecode(meshstack_building_block.this.status.outputs["storage_account_resource_group"].value), "rg-st") + error_message = "expected storage_account_resource_group to start with 'rg-st', got ${jsondecode(meshstack_building_block.this.status.outputs["storage_account_resource_group"].value)}" } } diff --git a/modules/meshstack/github-workflow/e2e/main.tf b/modules/meshstack/github-workflow/e2e/main.tf index a105896b..7c152cdf 100644 --- a/modules/meshstack/github-workflow/e2e/main.tf +++ b/modules/meshstack/github-workflow/e2e/main.tf @@ -50,7 +50,7 @@ locals { execution_mode = try(var.test_context.fixtures.github.async, false) ? "async" : "sync" } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { @@ -64,7 +64,7 @@ resource "meshstack_building_block_v2" "this" { inputs = { environment = { - value_string = "dev" + value = jsonencode("dev") } } } diff --git a/modules/meshstack/github-workflow/e2e/tests/meshstack_github_workflow_hub.tftest.hcl b/modules/meshstack/github-workflow/e2e/tests/meshstack_github_workflow_hub.tftest.hcl index 6dcc02e7..5bb05ad2 100644 --- a/modules/meshstack/github-workflow/e2e/tests/meshstack_github_workflow_hub.tftest.hcl +++ b/modules/meshstack/github-workflow/e2e/tests/meshstack_github_workflow_hub.tftest.hcl @@ -1,16 +1,16 @@ run "meshstack_github_workflow_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "github workflow hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "github workflow hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = !try(var.test_context.fixtures.github.async, false) || try(length(meshstack_building_block_v2.this.status.outputs["run_url"].value_string) > 0, false) + condition = !try(var.test_context.fixtures.github.async, false) || try(length(jsondecode(meshstack_building_block.this.status.outputs["run_url"].value)) > 0, false) error_message = "github workflow hub building block expected non-empty run_url output in async mode" } assert { - condition = !try(var.test_context.fixtures.github.async, false) || try(can(regex("^https?://", meshstack_building_block_v2.this.status.outputs["run_url"].value_string)), false) + condition = !try(var.test_context.fixtures.github.async, false) || try(can(regex("^https?://", jsondecode(meshstack_building_block.this.status.outputs["run_url"].value))), false) error_message = "github workflow hub building block expected async run_url output to look like an URL" } } diff --git a/modules/meshstack/manual/e2e/main.tf b/modules/meshstack/manual/e2e/main.tf index 1a5c43b4..16938ecc 100644 --- a/modules/meshstack/manual/e2e/main.tf +++ b/modules/meshstack/manual/e2e/main.tf @@ -20,7 +20,7 @@ module "manual" { } } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = module.manual.building_block_definition.version_ref @@ -32,10 +32,10 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - text = { value_string = "Hello, Manual World!" } - flag = { value_bool = true } - num = { value_int = 42 } - single_select = { value_single_select = "option1" } + text = { value = jsonencode("Hello, Manual World!") } + flag = { value = jsonencode(true) } + num = { value = jsonencode(42) } + single_select = { value = jsonencode("option1") } # static_note is STATIC — provided in the BBD, not by the user } } diff --git a/modules/meshstack/manual/e2e/tests/building_block_manual_hub.tftest.hcl b/modules/meshstack/manual/e2e/tests/building_block_manual_hub.tftest.hcl index edce612c..40a4e3f0 100644 --- a/modules/meshstack/manual/e2e/tests/building_block_manual_hub.tftest.hcl +++ b/modules/meshstack/manual/e2e/tests/building_block_manual_hub.tftest.hcl @@ -1,27 +1,27 @@ run "building_block_manual_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "manual hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "manual hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["text"].value_string == "Hello, Manual World!" - error_message = "manual hub building block expected output text to be 'Hello, Manual World!', got ${meshstack_building_block_v2.this.status.outputs["text"].value_string}" + condition = jsondecode(meshstack_building_block.this.status.outputs["text"].value) == "Hello, Manual World!" + error_message = "manual hub building block expected output text to be 'Hello, Manual World!', got ${jsondecode(meshstack_building_block.this.status.outputs["text"].value)}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["flag"].value_bool == true - error_message = "manual hub building block expected output flag to be true, got ${meshstack_building_block_v2.this.status.outputs["flag"].value_bool}" + condition = jsondecode(meshstack_building_block.this.status.outputs["flag"].value) == true + error_message = "manual hub building block expected output flag to be true, got ${jsondecode(meshstack_building_block.this.status.outputs["flag"].value)}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["num"].value_int == 42 - error_message = "manual hub building block expected output num to be 42, got ${meshstack_building_block_v2.this.status.outputs["num"].value_int}" + condition = jsondecode(meshstack_building_block.this.status.outputs["num"].value) == 42 + error_message = "manual hub building block expected output num to be 42, got ${jsondecode(meshstack_building_block.this.status.outputs["num"].value)}" } # SINGLE_SELECT inputs are mirrored to a STRING output by the manual runner. assert { - condition = meshstack_building_block_v2.this.status.outputs["single_select"].value_string == "option1" - error_message = "manual hub building block expected output single_select to be 'option1', got ${meshstack_building_block_v2.this.status.outputs["single_select"].value_string}" + condition = jsondecode(meshstack_building_block.this.status.outputs["single_select"].value) == "option1" + error_message = "manual hub building block expected output single_select to be 'option1', got ${jsondecode(meshstack_building_block.this.status.outputs["single_select"].value)}" } } diff --git a/modules/meshstack/noop/e2e/env-audit/main.tf b/modules/meshstack/noop/e2e/env-audit/main.tf index 0cf5a47e..fff56389 100644 --- a/modules/meshstack/noop/e2e/env-audit/main.tf +++ b/modules/meshstack/noop/e2e/env-audit/main.tf @@ -55,7 +55,7 @@ resource "meshstack_building_block_definition" "env_audit" { } } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = meshstack_building_block_definition.env_audit.version_latest diff --git a/modules/meshstack/noop/e2e/main.tf b/modules/meshstack/noop/e2e/main.tf index d108ea04..5aedc3fd 100644 --- a/modules/meshstack/noop/e2e/main.tf +++ b/modules/meshstack/noop/e2e/main.tf @@ -20,7 +20,7 @@ module "noop" { } } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = module.noop.building_block_definition.version_ref @@ -32,13 +32,13 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - flag = { value_bool = true } - num = { value_int = 1 } - text = { value_string = "Hello, World!" } - sensitive_text = { value_string_sensitive = "Hidden value" } - single_select = { value_single_select = "single1" } - multi_select = { value_multi_select = ["multi1", "multi2"] } - multi_select_json = { value_multi_select = ["multi2", "multi1"] } + flag = { value = jsonencode(true) } + num = { value = jsonencode(1) } + text = { value = jsonencode("Hello, World!") } + sensitive_text = { sensitive = { secret_value = "Hidden value" } } + single_select = { value = jsonencode("single1") } + multi_select = { value = jsonencode(["multi1", "multi2"]) } + multi_select_json = { value = jsonencode(["multi2", "multi1"]) } } } } diff --git a/modules/meshstack/noop/e2e/runner/main.tf b/modules/meshstack/noop/e2e/runner/main.tf index 1e54b280..dd468f56 100644 --- a/modules/meshstack/noop/e2e/runner/main.tf +++ b/modules/meshstack/noop/e2e/runner/main.tf @@ -23,7 +23,7 @@ module "noop" { depends_on = [module.backplane] # Without the backplane there is no runner and no place to run the BB. } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = module.noop.building_block_definition.version_ref @@ -35,13 +35,13 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - flag = { value_bool = true } - num = { value_int = 1 } - text = { value_string = "Hello, World!" } - sensitive_text = { value_string_sensitive = "Hidden value" } - single_select = { value_single_select = "single1" } - multi_select = { value_multi_select = ["multi1", "multi2"] } - multi_select_json = { value_multi_select = ["multi2", "multi1"] } + flag = { value = jsonencode(true) } + num = { value = jsonencode(1) } + text = { value = jsonencode("Hello, World!") } + sensitive_text = { sensitive = { secret_value = "Hidden value" } } + single_select = { value = jsonencode("single1") } + multi_select = { value = jsonencode(["multi1", "multi2"]) } + multi_select_json = { value = jsonencode(["multi2", "multi1"]) } } } diff --git a/modules/meshstack/noop/e2e/tests/building_block_noop_hub.tftest.hcl b/modules/meshstack/noop/e2e/tests/building_block_noop_hub.tftest.hcl index 86e87a76..52d2b0d0 100644 --- a/modules/meshstack/noop/e2e/tests/building_block_noop_hub.tftest.hcl +++ b/modules/meshstack/noop/e2e/tests/building_block_noop_hub.tftest.hcl @@ -1,36 +1,36 @@ run "building_block_noop_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "noop hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "noop hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["num"].value_int == 1 - error_message = "noop hub building block expected output num to be 1, got ${meshstack_building_block_v2.this.status.outputs["num"].value_int}" + condition = jsondecode(meshstack_building_block.this.status.outputs["num"].value) == 1 + error_message = "noop hub building block expected output num to be 1, got ${jsondecode(meshstack_building_block.this.status.outputs["num"].value)}" } assert { - condition = startswith(meshstack_building_block_v2.this.status.outputs["text"].value_string, "Hello, World! aws-cli/2") - error_message = "noop hub building block expected output text to start with 'Hello, World! aws-cli/2', got ${meshstack_building_block_v2.this.status.outputs["text"].value_string}" + condition = startswith(jsondecode(meshstack_building_block.this.status.outputs["text"].value), "Hello, World! aws-cli/2") + error_message = "noop hub building block expected output text to start with 'Hello, World! aws-cli/2', got ${jsondecode(meshstack_building_block.this.status.outputs["text"].value)}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["flag"].value_bool == true - error_message = "noop hub building block expected output flag to be true, got ${meshstack_building_block_v2.this.status.outputs["flag"].value_bool}" + condition = jsondecode(meshstack_building_block.this.status.outputs["flag"].value) == true + error_message = "noop hub building block expected output flag to be true, got ${jsondecode(meshstack_building_block.this.status.outputs["flag"].value)}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["resource_url"].value_string == "https://hub.meshcloud.io/modules/meshstack/noop" - error_message = "noop hub building block expected output resource_url to be 'https://hub.meshcloud.io/modules/meshstack/noop', got ${meshstack_building_block_v2.this.status.outputs["resource_url"].value_string}" + condition = jsondecode(meshstack_building_block.this.status.outputs["resource_url"].value) == "https://hub.meshcloud.io/modules/meshstack/noop" + error_message = "noop hub building block expected output resource_url to be 'https://hub.meshcloud.io/modules/meshstack/noop', got ${jsondecode(meshstack_building_block.this.status.outputs["resource_url"].value)}" } assert { condition = ( - meshstack_building_block_v2.this.status.outputs["summary"].value_string + jsondecode(meshstack_building_block.this.status.outputs["summary"].value) == file("${path.root}/tests/building_block_noop_hub.summary.expected.md") ) - error_message = "noop hub building block expected output summary to match expected, got ${meshstack_building_block_v2.this.status.outputs["summary"].value_string}" + error_message = "noop hub building block expected output summary to match expected, got ${jsondecode(meshstack_building_block.this.status.outputs["summary"].value)}" } assert { @@ -38,7 +38,7 @@ run "building_block_noop_hub" { # and permissions may change, so we assert those separately below condition = ( { - for k, v in jsondecode(meshstack_building_block_v2.this.status.outputs["debug_input_variables_json"].value_code) : + for k, v in jsondecode(jsondecode(meshstack_building_block.this.status.outputs["debug_input_variables_json"].value)) : k => v if k != "user_permissions_json" && k != "user_permissions" } @@ -50,7 +50,7 @@ run "building_block_noop_hub" { assert { condition = contains( - jsondecode(meshstack_building_block_v2.this.status.outputs["debug_input_variables_json"].value_code)["user_permissions"], + jsondecode(jsondecode(meshstack_building_block.this.status.outputs["debug_input_variables_json"].value))["user_permissions"], jsondecode(file("${path.root}/tests/building_block_noop_hub.debug_input_variables_json_binding.expected.json")) ) error_message = "could not find expected user permission" @@ -59,7 +59,7 @@ run "building_block_noop_hub" { assert { condition = contains( # double decoding is required when user_permissions_json is passed as json - jsondecode(jsondecode(meshstack_building_block_v2.this.status.outputs["debug_input_variables_json"].value_code)["user_permissions_json"]), + jsondecode(jsondecode(jsondecode(meshstack_building_block.this.status.outputs["debug_input_variables_json"].value))["user_permissions_json"]), jsondecode(file("${path.root}/tests/building_block_noop_hub.debug_input_variables_json_binding.expected.json")) ) error_message = "could not find expected user permission" @@ -67,11 +67,10 @@ run "building_block_noop_hub" { assert { condition = ( - jsondecode(meshstack_building_block_v2.this.status.outputs["debug_input_files_json"].value_code) + jsondecode(jsondecode(meshstack_building_block.this.status.outputs["debug_input_files_json"].value)) == jsondecode(file("${path.root}/tests/building_block_noop_hub.debug_input_files_json.expected.json")) ) - error_message = "noop hub building block expected output debug_input_files_json to match expected, got ${meshstack_building_block_v2.this.status.outputs["debug_input_files_json"].value_code}" + error_message = "noop hub building block expected output debug_input_files_json to match expected, got ${jsondecode(jsondecode(meshstack_building_block.this.status.outputs["debug_input_files_json"].value))}" } } - diff --git a/modules/meshstack/noop/e2e/tests/building_block_noop_runner_hub.tftest.hcl b/modules/meshstack/noop/e2e/tests/building_block_noop_runner_hub.tftest.hcl index 844a52fc..381cbb26 100644 --- a/modules/meshstack/noop/e2e/tests/building_block_noop_runner_hub.tftest.hcl +++ b/modules/meshstack/noop/e2e/tests/building_block_noop_runner_hub.tftest.hcl @@ -4,22 +4,22 @@ run "building_block_noop_runner_hub" { } assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "noop runner building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "noop runner building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["num"].value_int == 1 - error_message = "noop runner building block expected output num to be 1, got ${meshstack_building_block_v2.this.status.outputs["num"].value_int}" + condition = jsondecode(meshstack_building_block.this.status.outputs["num"].value) == 1 + error_message = "noop runner building block expected output num to be 1, got ${jsondecode(meshstack_building_block.this.status.outputs["num"].value)}" } assert { - condition = startswith(meshstack_building_block_v2.this.status.outputs["text"].value_string, "Hello, World! aws-cli/2") - error_message = "noop runner building block expected output text to start with 'Hello, World! aws-cli/2', got ${meshstack_building_block_v2.this.status.outputs["text"].value_string}" + condition = startswith(jsondecode(meshstack_building_block.this.status.outputs["text"].value), "Hello, World! aws-cli/2") + error_message = "noop runner building block expected output text to start with 'Hello, World! aws-cli/2', got ${jsondecode(meshstack_building_block.this.status.outputs["text"].value)}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["flag"].value_bool == true - error_message = "noop runner building block expected output flag to be true, got ${meshstack_building_block_v2.this.status.outputs["flag"].value_bool}" + condition = jsondecode(meshstack_building_block.this.status.outputs["flag"].value) == true + error_message = "noop runner building block expected output flag to be true, got ${jsondecode(meshstack_building_block.this.status.outputs["flag"].value)}" } } diff --git a/modules/meshstack/noop/e2e/tests/env_audit_hub.tftest.hcl b/modules/meshstack/noop/e2e/tests/env_audit_hub.tftest.hcl index b7416967..b546cd43 100644 --- a/modules/meshstack/noop/e2e/tests/env_audit_hub.tftest.hcl +++ b/modules/meshstack/noop/e2e/tests/env_audit_hub.tftest.hcl @@ -4,22 +4,22 @@ run "env_audit_hub" { } assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "env-audit building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "env-audit building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { condition = length(setsubtract( - toset(jsondecode(meshstack_building_block_v2.this.status.outputs["prerun_env_keys"].value_string)), + toset(jsondecode(jsondecode(meshstack_building_block.this.status.outputs["prerun_env_keys"].value))), toset(jsondecode(file("${path.root}/allowed_env_keys.expected.json"))) )) == 0 - error_message = "Unexpected prerun environment variables detected: ${meshstack_building_block_v2.this.status.outputs["prerun_env_keys"].value_string}" + error_message = "Unexpected prerun environment variables detected: ${jsondecode(meshstack_building_block.this.status.outputs["prerun_env_keys"].value)}" } assert { # apply-time adds OpenTofu plugin protocol vars not present at prerun condition = length(setsubtract( - toset(jsondecode(meshstack_building_block_v2.this.status.outputs["apply_env_keys"].value_string)), + toset(jsondecode(jsondecode(meshstack_building_block.this.status.outputs["apply_env_keys"].value))), setunion( toset(jsondecode(file("${path.root}/allowed_env_keys.expected.json"))), toset([ @@ -32,6 +32,6 @@ run "env_audit_hub" { ]) ) )) == 0 - error_message = "Unexpected apply-time environment variables detected: ${meshstack_building_block_v2.this.status.outputs["apply_env_keys"].value_string}" + error_message = "Unexpected apply-time environment variables detected: ${jsondecode(meshstack_building_block.this.status.outputs["apply_env_keys"].value)}" } } diff --git a/modules/ske/ske-starterkit/e2e/main.tf b/modules/ske/ske-starterkit/e2e/main.tf index bf1dda04..cffcfbcd 100644 --- a/modules/ske/ske-starterkit/e2e/main.tf +++ b/modules/ske/ske-starterkit/e2e/main.tf @@ -162,7 +162,7 @@ module "ske_starterkit" { } } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = module.ske_starterkit.building_block_definition.version_ref @@ -174,7 +174,7 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - name = { value_string = "smoke-test-${var.test_context.name_suffix}" } + name = { value = jsonencode("smoke-test-${var.test_context.name_suffix}") } } } diff --git a/modules/ske/ske-starterkit/e2e/tests/building_block_ske_starterkit_hub.tftest.hcl b/modules/ske/ske-starterkit/e2e/tests/building_block_ske_starterkit_hub.tftest.hcl index 5036f86f..3e24904f 100644 --- a/modules/ske/ske-starterkit/e2e/tests/building_block_ske_starterkit_hub.tftest.hcl +++ b/modules/ske/ske-starterkit/e2e/tests/building_block_ske_starterkit_hub.tftest.hcl @@ -1,17 +1,17 @@ run "building_block_ske_starterkit_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "ske-starterkit hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "ske-starterkit hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = can(regex("^https://", meshstack_building_block_v2.this.status.outputs["app_link_dev"].value_string)) - error_message = "ske-starterkit hub building block expected app_link_dev to be a URL, got ${meshstack_building_block_v2.this.status.outputs["app_link_dev"].value_string}" + condition = can(regex("^https://", jsondecode(meshstack_building_block.this.status.outputs["app_link_dev"].value))) + error_message = "ske-starterkit hub building block expected app_link_dev to be a URL, got ${jsondecode(meshstack_building_block.this.status.outputs["app_link_dev"].value)}" } assert { - condition = can(regex("^https://", meshstack_building_block_v2.this.status.outputs["app_link_prod"].value_string)) - error_message = "ske-starterkit hub building block expected app_link_prod to be a URL, got ${meshstack_building_block_v2.this.status.outputs["app_link_prod"].value_string}" + condition = can(regex("^https://", jsondecode(meshstack_building_block.this.status.outputs["app_link_prod"].value))) + error_message = "ske-starterkit hub building block expected app_link_prod to be a URL, got ${jsondecode(meshstack_building_block.this.status.outputs["app_link_prod"].value)}" } # The app must actually serve traffic over a valid (cert-manager-issued) TLS certificate. diff --git a/modules/stackit/git-repository/e2e/main.tf b/modules/stackit/git-repository/e2e/main.tf index 5a0c4fe4..f5720adf 100644 --- a/modules/stackit/git-repository/e2e/main.tf +++ b/modules/stackit/git-repository/e2e/main.tf @@ -43,7 +43,7 @@ locals { version_ref = var.test_context.bbd_version_ref != null ? var.test_context.bbd_version_ref : module.stackit_git_repository[0].building_block_definition.version_ref } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { wait_for_completion = true spec = { building_block_definition_version_ref = { uuid = local.version_ref.uuid } @@ -55,10 +55,10 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - name = { value_string = "smoke-test-repo-${var.test_context.name_suffix}" } - description = { value_string = "Smoke test repository" } - private = { value_bool = true } - clone_addr = { value_string = "https://github.com/likvid-bank/starterkit-template-stackit-ai-summarizer.git" } + name = { value = jsonencode("smoke-test-repo-${var.test_context.name_suffix}") } + description = { value = jsonencode("Smoke test repository") } + private = { value = jsonencode(true) } + clone_addr = { value = jsonencode("https://github.com/likvid-bank/starterkit-template-stackit-ai-summarizer.git") } } } } diff --git a/modules/stackit/git-repository/e2e/tests/building_block_stackit_git-repository_hub.tftest.hcl b/modules/stackit/git-repository/e2e/tests/building_block_stackit_git-repository_hub.tftest.hcl index ba7d222c..241d5462 100644 --- a/modules/stackit/git-repository/e2e/tests/building_block_stackit_git-repository_hub.tftest.hcl +++ b/modules/stackit/git-repository/e2e/tests/building_block_stackit_git-repository_hub.tftest.hcl @@ -1,16 +1,16 @@ run "building_block_stackit_git_repository_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "stackit git-repository hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "stackit git-repository hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = strcontains(meshstack_building_block_v2.this.status.outputs["summary"].value_string, "is ready on STACKIT Git Forgejo") - error_message = "stackit git-repository hub building block expected summary to contain 'is ready on STACKIT Git Forgejo', got ${meshstack_building_block_v2.this.status.outputs["summary"].value_string}" + condition = strcontains(jsondecode(meshstack_building_block.this.status.outputs["summary"].value), "is ready on STACKIT Git Forgejo") + error_message = "stackit git-repository hub building block expected summary to contain 'is ready on STACKIT Git Forgejo', got ${jsondecode(meshstack_building_block.this.status.outputs["summary"].value)}" } assert { - condition = can(regex("^${var.test_context.forgejo_base_url}/${var.test_context.forgejo_organization}/smoke-test-repo-\\d+\\.git$", meshstack_building_block_v2.this.status.outputs["repository_clone_url"].value_string)) - error_message = "stackit git-repository hub building block expected repository_clone_url to match pattern, got ${meshstack_building_block_v2.this.status.outputs["repository_clone_url"].value_string}" + condition = can(regex("^${var.test_context.forgejo_base_url}/${var.test_context.forgejo_organization}/smoke-test-repo-\\d+\\.git$", jsondecode(meshstack_building_block.this.status.outputs["repository_clone_url"].value))) + error_message = "stackit git-repository hub building block expected repository_clone_url to match pattern, got ${jsondecode(meshstack_building_block.this.status.outputs["repository_clone_url"].value)}" } } diff --git a/modules/stackit/storage-bucket/e2e/main.tf b/modules/stackit/storage-bucket/e2e/main.tf index 2f563fe5..33d97c91 100644 --- a/modules/stackit/storage-bucket/e2e/main.tf +++ b/modules/stackit/storage-bucket/e2e/main.tf @@ -54,7 +54,7 @@ locals { version_ref = var.test_context.bbd_version_ref != null ? var.test_context.bbd_version_ref : module.stackit_storage_bucket[0].building_block_definition.version_ref } -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { # Explicit dependency ensures the building block (and its delete run) is fully destroyed before # any backplane resources are torn down. Without this, OpenTofu destroys the WIF federated # identity providers in parallel with the delete run, causing 401s from the STACKIT provider. @@ -70,7 +70,7 @@ resource "meshstack_building_block_v2" "this" { } inputs = { - bucket_name = { value_string = "smoke-test-bucket-${var.test_context.name_suffix}" } + bucket_name = { value = jsonencode("smoke-test-bucket-${var.test_context.name_suffix}") } } } } diff --git a/modules/stackit/storage-bucket/e2e/tests/building_block_stackit_storage-bucket_hub.tftest.hcl b/modules/stackit/storage-bucket/e2e/tests/building_block_stackit_storage-bucket_hub.tftest.hcl index e3964fe1..110dc63d 100644 --- a/modules/stackit/storage-bucket/e2e/tests/building_block_stackit_storage-bucket_hub.tftest.hcl +++ b/modules/stackit/storage-bucket/e2e/tests/building_block_stackit_storage-bucket_hub.tftest.hcl @@ -1,26 +1,26 @@ run "building_block_stackit_storage_bucket_hub" { assert { - condition = meshstack_building_block_v2.this.status.status == "SUCCEEDED" - error_message = "stackit storage-bucket hub building block expected SUCCEEDED, got ${meshstack_building_block_v2.this.status.status}" + condition = meshstack_building_block.this.status.status == "SUCCEEDED" + error_message = "stackit storage-bucket hub building block expected SUCCEEDED, got ${meshstack_building_block.this.status.status}" } assert { - condition = meshstack_building_block_v2.this.status.outputs["bucket_name"].value_string == "smoke-test-bucket-${var.test_context.name_suffix}" - error_message = "stackit storage-bucket hub building block expected bucket_name to be 'smoke-test-bucket-${var.test_context.name_suffix}', got ${meshstack_building_block_v2.this.status.outputs["bucket_name"].value_string}" + condition = jsondecode(meshstack_building_block.this.status.outputs["bucket_name"].value) == "smoke-test-bucket-${var.test_context.name_suffix}" + error_message = "stackit storage-bucket hub building block expected bucket_name to be 'smoke-test-bucket-${var.test_context.name_suffix}', got ${jsondecode(meshstack_building_block.this.status.outputs["bucket_name"].value)}" } assert { - condition = strcontains(meshstack_building_block_v2.this.status.outputs["bucket_url_path_style"].value_string, "smoke-test-bucket-${var.test_context.name_suffix}") - error_message = "stackit storage-bucket hub building block expected bucket_url_path_style to contain bucket name, got ${meshstack_building_block_v2.this.status.outputs["bucket_url_path_style"].value_string}" + condition = strcontains(jsondecode(meshstack_building_block.this.status.outputs["bucket_url_path_style"].value), "smoke-test-bucket-${var.test_context.name_suffix}") + error_message = "stackit storage-bucket hub building block expected bucket_url_path_style to contain bucket name, got ${jsondecode(meshstack_building_block.this.status.outputs["bucket_url_path_style"].value)}" } assert { - condition = strcontains(meshstack_building_block_v2.this.status.outputs["bucket_url_path_style"].value_string, "object.storage.eu01.onstackit.cloud") - error_message = "stackit storage-bucket hub building block expected bucket_url_path_style to contain STACKIT domain, got ${meshstack_building_block_v2.this.status.outputs["bucket_url_path_style"].value_string}" + condition = strcontains(jsondecode(meshstack_building_block.this.status.outputs["bucket_url_path_style"].value), "object.storage.eu01.onstackit.cloud") + error_message = "stackit storage-bucket hub building block expected bucket_url_path_style to contain STACKIT domain, got ${jsondecode(meshstack_building_block.this.status.outputs["bucket_url_path_style"].value)}" } assert { - condition = length(meshstack_building_block_v2.this.status.outputs["s3_access_key"].value_string) > 0 + condition = length(jsondecode(meshstack_building_block.this.status.outputs["s3_access_key"].value)) > 0 error_message = "stackit storage-bucket hub building block expected non-empty s3_access_key" } } From 6ed5efa5632058b53ed2c8d50fb9de5cdfe2f3c5 Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Thu, 2 Jul 2026 20:21:57 +0200 Subject: [PATCH 3/5] docs: teach the e2e-test skill the meshstack_building_block input/output shape Update the e2e-test skill to use meshstack_building_block, the value = jsonencode(...) / sensitive input shape, and jsondecode(...value) output reads. Co-Authored-By: Claude Opus 4.8 (1M context) --- .agents/skills/e2e-test/SKILL.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.agents/skills/e2e-test/SKILL.md b/.agents/skills/e2e-test/SKILL.md index 8523b712..9a48e1cf 100644 --- a/.agents/skills/e2e-test/SKILL.md +++ b/.agents/skills/e2e-test/SKILL.md @@ -135,11 +135,11 @@ locals { } ``` -- Create a `meshstack_building_block_v2` resource that exercises the building block end-to-end. +- Create a `meshstack_building_block` resource that exercises the building block end-to-end. Reference `test_context` directly (it is non-null in both modes). The provider's `building_block_definition_version_ref` takes `{ uuid }` only — extract it explicitly. -- **Always add `depends_on = [module.]`** to `meshstack_building_block_v2.this`. +- **Always add `depends_on = [module.]`** to `meshstack_building_block.this`. WIF federated identity providers have no Terraform dependents (nothing references their outputs), so OpenTofu schedules their destruction in parallel with the BB delete run. This causes the BB delete run to fail with 401s because the cloud WIF trust is already gone before the delete run @@ -147,7 +147,7 @@ locals { be fully destroyed before any backplane resources are torn down. ```hcl -resource "meshstack_building_block_v2" "this" { +resource "meshstack_building_block" "this" { depends_on = [module.] # prevents teardown race with WIF providers wait_for_completion = true spec = { @@ -158,6 +158,9 @@ resource "meshstack_building_block_v2" "this" { kind = "meshWorkspace" name = var.test_context.workspace } + # inputs: one `value = jsonencode(...)` per input (jsonencode strings too, e.g. + # jsonencode("x"), jsonencode(1), jsonencode(true)). Sensitive inputs instead use + # `sensitive = { secret_value = ... }`. inputs = { ... } } } @@ -188,7 +191,8 @@ target_ref = { - Name the file `__hub.tftest.hcl` (e.g. `building_block_noop_hub.tftest.hcl`). - Always assert `status.status == "SUCCEEDED"` as the first check. - Assert meaningful output values (URLs, strings, booleans) to validate the building block executed - correctly. + correctly. Every output `value` is a `jsonencode`d string — read it with + `jsondecode(.status.outputs[""].value)` (a CODE/JSON output decodes twice). - The same test file runs in **both** invocation modes (smoke-test via `tofu test`, foundation via `terragrunt test`). Reference **`output.`**, never `var.test_context.*` — `test_context` is null in foundation mode and would crash the assertion. @@ -255,7 +259,7 @@ node tools/debug/get-bb-run-logs.mjs "$BB_UUID" To get the UUID from an errored test state: ```bash -tofu state show -state=errored_test.tfstate 'meshstack_building_block_v2.this' | grep uuid +tofu state show -state=errored_test.tfstate 'meshstack_building_block.this' | grep uuid ``` @@ -318,6 +322,6 @@ source setup-override-provider.sh - [ ] `hub.git_ref = var.test_context.hub_git_ref` — no hardcoded `"main"` - [ ] Version ref resolved in a `local` (`bbd_version_ref` in foundation mode, else the built module) - [ ] `building_block_definition_version_ref = { uuid = local.version_ref.uuid }` — provider only accepts `{ uuid }`, extract it explicitly -- [ ] `meshstack_building_block_v2` has `depends_on = [module.]` to prevent WIF teardown race (delete run must finish before backplane resources are destroyed) -- [ ] `meshstack_building_block_v2` has `wait_for_completion = true` +- [ ] `meshstack_building_block` has `depends_on = [module.]` to prevent WIF teardown race (delete run must finish before backplane resources are destroyed) +- [ ] `meshstack_building_block` has `wait_for_completion = true` - [ ] tftest asserts `status.status == "SUCCEEDED"` and key outputs (references `var.test_context.*` directly — non-null in both modes) From bf6e498023eecb69afb8143ea0caa46bb28c27bc Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Tue, 7 Jul 2026 13:11:47 +0200 Subject: [PATCH 4/5] fix(azure-vm): preserve v2 omit-semantics for OS-specific inputs Under v2, `value_string = os == "Linux" ? key : null` omitted the input when null. Migrated verbatim to v3, `value = jsonencode(... : null)` instead resolves to the string "null" and the provider marshals that to an explicit JSON null, sending it to the backend. Build inputs via merge() so ssh_public_key / admin_password are only present for the matching OS, restoring the omit-on-null behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../buildingblock/main.tf | 61 +++++++++++-------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf index 00517db0..c9b232ff 100644 --- a/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf +++ b/modules/azure/azure-virtual-machine-starterkit/buildingblock/main.tf @@ -61,32 +61,41 @@ resource "meshstack_building_block" "azure_vm" { uuid = meshstack_tenant_v4.vm_tenant.metadata.uuid } display_name = "Azure Virtual Machine" - inputs = { - vm_name = { - value = jsonencode(local.identifier) - } - location = { - value = jsonencode(var.vm_location) - } - os_type = { - value = jsonencode(var.vm_os_type) - } - vm_size = { - value = jsonencode(var.vm_size) - } - admin_username = { - value = jsonencode(var.vm_admin_username) - } - enable_public_ip = { - value = jsonencode(var.vm_enable_public_ip) - } - ssh_public_key = { - value = jsonencode(var.vm_os_type == "Linux" ? var.vm_ssh_public_key : null) - } - admin_password = { - value = jsonencode(var.vm_os_type == "Windows" ? var.vm_admin_password : null) - } - } + inputs = merge( + { + vm_name = { + value = jsonencode(local.identifier) + } + location = { + value = jsonencode(var.vm_location) + } + os_type = { + value = jsonencode(var.vm_os_type) + } + vm_size = { + value = jsonencode(var.vm_size) + } + admin_username = { + value = jsonencode(var.vm_admin_username) + } + enable_public_ip = { + value = jsonencode(var.vm_enable_public_ip) + } + }, + # Only send the OS-specific credential input for the matching OS. This mirrors + # the pre-v3 behavior where a null `value_string` omitted the input entirely; + # under v3 a `jsonencode(... : null)` would instead send an explicit JSON null. + var.vm_os_type == "Linux" ? { + ssh_public_key = { + value = jsonencode(var.vm_ssh_public_key) + } + } : {}, + var.vm_os_type == "Windows" ? { + admin_password = { + value = jsonencode(var.vm_admin_password) + } + } : {}, + ) } } From c4c225b8ac6dcef9090929d3b5d90b7532da539f Mon Sep 17 00:00:00 2001 From: Andreas Grub Date: Tue, 7 Jul 2026 13:21:24 +0200 Subject: [PATCH 5/5] fix(ske/e2e): migrate endpoint-probe BB output ref to v3 main's endpoint-probe data source (added after this branch was cut) referenced meshstack_building_block_v2.this; the e2e resource is now meshstack_building_block.this. Point the probe at the v3 resource and jsondecode the output value. Surfaced when rebasing the migration onto current main. Co-Authored-By: Claude Opus 4.8 (1M context) --- modules/ske/ske-starterkit/e2e/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ske/ske-starterkit/e2e/main.tf b/modules/ske/ske-starterkit/e2e/main.tf index cffcfbcd..0ada8150 100644 --- a/modules/ske/ske-starterkit/e2e/main.tf +++ b/modules/ske/ske-starterkit/e2e/main.tf @@ -190,6 +190,6 @@ data "external" "app_probe" { for_each = toset(["dev", "prod"]) program = ["python3", "${path.module}/probe_endpoint.py"] query = { - url = meshstack_building_block_v2.this.status.outputs["app_link_${each.key}"].value_string + url = jsondecode(meshstack_building_block.this.status.outputs["app_link_${each.key}"].value) } }