diff --git a/.agents/skills/module/SKILL.md b/.agents/skills/module/SKILL.md index 6e377ace..9389c6a8 100644 --- a/.agents/skills/module/SKILL.md +++ b/.agents/skills/module/SKILL.md @@ -37,6 +37,7 @@ conventions, see the reference files in `.agents/references/`. 5. **Write the BBD readme** → `.agents/references/bbd-readme.md` 6. **Write `meshstack_integration.tf`** — follow AGENTS.md § `meshstack_integration.tf` Conventions + - Always add `lifecycle { ignore_changes = [ availability ] }` to every `meshstack_platform` resource (see AGENTS.md § `meshstack_platform` Lifecycle) 7. **Validate**: ```sh diff --git a/AGENTS.md b/AGENTS.md index 7276e3a3..9fba8b9a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -159,6 +159,22 @@ resource "meshstack_building_block_definition" "this" { } ``` + +### `meshstack_platform` Lifecycle + +Every `meshstack_platform` resource must include a `lifecycle` block that ignores changes to `availability`: + +```hcl +resource "meshstack_platform" "this" { + # ... + lifecycle { + ignore_changes = [spec.availability] + } +} +``` + +The `availability` field controls publication state and access restrictions. meshStack operators modify this after initial deployment (e.g. to publish a platform to users) — Terraform must not reset it on subsequent applies. + --- @@ -336,5 +352,6 @@ See [.agents/skills/write-e2e-test/SKILL.md](.agents/skills/write-e2e-test/SKILL - [ ] `meshstack` and `hub` variables are at the end of the variable section - [ ] `logo.png` included in `buildingblock/` - [ ] No `documentation_md` output in `backplane/` — use BBD `readme` field and `backplane/README.md` instead +- [ ] `meshstack_platform` resources include `lifecycle { ignore_changes = [spec.availability] }` - [ ] No trailing whitespace - [ ] **Azure modules**: also follow the [Azure Backplane Checklist](.agents/skills/azure-backplane.md#checklist-for-azure-backplanes) diff --git a/modules/aks/meshstack_integration.tf b/modules/aks/meshstack_integration.tf index 4ae52af0..b7b5c40f 100644 --- a/modules/aks/meshstack_integration.tf +++ b/modules/aks/meshstack_integration.tf @@ -117,6 +117,10 @@ resource "meshstack_platform" "aks" { } } } + + lifecycle { + ignore_changes = [spec.availability] + } } resource "meshstack_landingzone" "aks_default" { diff --git a/modules/azure/meshstack_integration.tf b/modules/azure/meshstack_integration.tf index 9beeba49..eb32cbc1 100644 --- a/modules/azure/meshstack_integration.tf +++ b/modules/azure/meshstack_integration.tf @@ -211,6 +211,10 @@ resource "meshstack_platform" "azure" { } } } + + lifecycle { + ignore_changes = [spec.availability] + } } resource "meshstack_landingzone" "azure_default" { diff --git a/modules/ske/ske-starterkit/e2e/meshstack_kubernetes_platform/main.tf b/modules/ske/ske-starterkit/e2e/meshstack_kubernetes_platform/main.tf index c200079b..cdfa9018 100644 --- a/modules/ske/ske-starterkit/e2e/meshstack_kubernetes_platform/main.tf +++ b/modules/ske/ske-starterkit/e2e/meshstack_kubernetes_platform/main.tf @@ -146,6 +146,10 @@ resource "meshstack_platform" "this" { contributing_workspaces = [] } + + lifecycle { + ignore_changes = [spec.availability] + } } # dev meshLandingZone diff --git a/modules/stackit/meshstack_integration.tf b/modules/stackit/meshstack_integration.tf index 0eed9915..d089ed55 100644 --- a/modules/stackit/meshstack_integration.tf +++ b/modules/stackit/meshstack_integration.tf @@ -73,6 +73,10 @@ resource "meshstack_platform" "stackit" { owned_by_workspace = var.meshstack.owning_workspace_identifier } + lifecycle { + ignore_changes = [spec.availability] + } + spec = { display_name = "STACKIT Project" description = "Create a STACKIT project with role-based access control." diff --git a/tools/scorecard/scorecard.mjs b/tools/scorecard/scorecard.mjs index af219b74..72e05449 100755 --- a/tools/scorecard/scorecard.mjs +++ b/tools/scorecard/scorecard.mjs @@ -310,6 +310,22 @@ const detectors = [ }; }, }, + { + id: "platform_lifecycle_ignore_availability", + category: "integration", + name: "meshstack_platform has lifecycle ignore_changes = [availability]", + emoji: "🔄", + fn: (mod) => { + const content = readIntegrationTf(mod); + if (!content) return { pass: false, detail: "no integration file" }; + const hasPlatformResource = /resource\s+"meshstack_platform"/.test(content); + if (!hasPlatformResource) return { pass: null, detail: "no meshstack_platform resource" }; + return { + pass: /lifecycle\s*\{[\s\S]*?ignore_changes\s*=\s*\[[^\]]*spec\.availability[^\]]*\]/.test(content), + detail: "add lifecycle { ignore_changes = [spec.availability] } to meshstack_platform resource", + }; + }, + }, // ─── Azure Backplane ──────────────────────────────────────────────────── {