Skip to content

Detect and report Azure Landing Zone context in target environment (with repo/org-level override) #14

@arnaudlh

Description

@arnaudlh

Summary

Git-Ape should automatically discover whether the target Azure environment is governed by a Landing Zone (e.g., Azure Landing Zone / ALZ, Sovereign Landing Zone / SLZ, Financial Services LZ, or a custom/CAF-aligned variant) and echo what it finds to the user before entering the deployment pipeline. When auto-detection is ambiguous or intentionally bypassed, users should be able to force a specific landing zone context via repo-level (and optionally org-level) configuration.

This is foundational for downstream agents/skills (Requirements Gatherer, Template Generator, Security Analyzer, Principal Architect, Role Selector) so that generated ARM templates, naming, policies, networking, and RBAC align with the LZ's guardrails instead of fighting them.

Motivation

Today @git-ape generates ARM templates and runs security/preflight/cost checks without awareness that the subscription may sit under an ALZ management group hierarchy with deployIfNotExists policies, mandated diagnostic settings, hub-spoke networking, required tags, custom RBAC, or Private DNS zones in a central subscription. This causes:

  • Preflight/what-if surprises (policy denies, modify effects).
  • Security analyzer findings that are already handled by the LZ (noise).
  • Template Generator proposing networking that conflicts with the hub.
  • Naming drift vs. the LZ's enforced CAF abbreviations.

Detecting and echoing the LZ context early lets the pipeline adapt (and tells the user why).

Scope

Add a new skill (and supporting agent hook) that:

  1. Discovers landing zone signals in the current Azure context.
  2. Classifies the environment as one of: alz, slz, caf-custom, none, or unknown.
  3. Echoes a human-readable summary + a structured record saved under .azure/deployments/ for reuse.
  4. Honors a repo/org-level override that forces a specific LZ profile or disables detection entirely.

Proposed skill name: /azure-landing-zone-detector (sits alongside /prereq-check as a Pre-Deploy/context skill, runs early — before azure-naming-research).

Detection strategy (discovery heuristics)

The skill should combine multiple signals rather than relying on a single check. Confidence score = weighted sum; echo signals found.

A. Management group hierarchy

  • az account management-group list + show --expand --recursive
  • Look for canonical ALZ MG names/IDs: alz, Tenant Root Group children named Platform, Landing Zones, Decommissioned, Sandbox, Connectivity, Identity, Management, Corp, Online.
  • Detect SLZ markers: Confidential Corp, Confidential Online, sovereignty-related naming.

B. Policy assignments at MG/subscription scope

  • az policy assignment list --scope <mg-or-sub>
  • Match known ALZ initiative definition IDs / display names (e.g., Deploy-MDFC-Config, Deploy-Diagnostics-*, Enforce-*, Audit-* initiatives published by the ALZ reference implementation).
  • Presence of Microsoft Cloud Security Benchmark + ALZ custom initiatives = strong signal.

C. Known platform resource groups / resources

  • Look in connectivity/management/identity subscriptions (or current sub) for:
    • rg-*-connectivity-*, rg-*-management-*, rg-*-identity-*, rg-hub-*
    • Central Log Analytics workspace, Automation Account, hub VNet + Azure Firewall / VWAN, Private DNS zones following ALZ list.

D. Tags and subscription metadata

  • Subscription display name patterns (sub-<env>-<lz>-<workload>).
  • Required tags coming from policy modify effects (e.g., Environment, CostCenter, Owner).

E. Deployment/IaC fingerprints

  • Look for ALZ / AVM deployment stamps (Bicep/Terraform module metadata on resource groups), ALZ Accelerator tags, managedBy fields.
  • Check for Azure Verified Modules (AVM) module outputs if present in state.

F. Optional agentic signal

  • Delegate a probe to the Azure MCP server or a lightweight sub-skill to query the hierarchy. Azure MCP is already a prerequisite per docs/AZURE_MCP_SETUP.md, so reuse it.
  • Consider delegating to azure-principal-architect for ambiguous cases (human-in-the-loop classification).

Output contract

Emit both:

  • User echo (chat) — e.g.:

    🦍 Detected Azure Landing Zone (ALZ) context
    • Management group path: Tenant Root > alz > Landing Zones > Corp > sub-corp-prod-01
    • 27 ALZ policy assignments in scope (3 deny, 19 deployIfNotExists, 5 audit)
    • Central Log Analytics: /subscriptions/.../rg-alz-management-prod/providers/.../log-alz-prod
    • Hub VNet detected in connectivity subscription
    Confidence: high (0.92) — I'll align naming, networking, and RBAC to ALZ guardrails.

  • Structured record saved to .azure/deployments/landing-zone.json:
    {
      "profile": "alz",
      "confidence": 0.92,
      "detectedAt": "2026-04-21T12:34:56Z",
      "source": "auto",
      "managementGroupPath": ["Tenant Root", "alz", "Landing Zones", "Corp"],
      "policyInitiatives": ["Deploy-MDFC-Config", "Enforce-ALZ-Decomm", "..."],
      "platformSubscriptions": { "connectivity": "...", "management": "...", "identity": "..." },
      "hub": { "vnetId": "...", "firewall": "azfw", "privateDnsZones": 47 },
      "requiredTags": ["Environment", "CostCenter", "Owner"],
      "namingConvention": "caf"
    }

Override / force mechanism

Multiple layers, with clear precedence (highest wins):

  1. Interactive chat flag — e.g. @git-ape deploy ... --landing-zone=alz or /landing-zone set alz.
  2. Environment variableGIT_APE_LANDING_ZONE=alz|slz|caf-custom|none|auto. Useful in headless/Actions mode.
  3. Repo-level config — new file .azure/git-ape.yml (or extend plugin.json consumer config):
    landingZone:
      mode: force          # auto | force | disabled
      profile: alz         # alz | slz | caf-custom | none
      customProfile:       # only when profile: caf-custom
        managementGroupRoot: "contoso"
        namingConvention: "caf"
        requiredTags: [Environment, CostCenter, Owner]
        hubSubscriptionId: "..."
      detection:
        skipSignals: [policy]   # optional: skip expensive probes
        minConfidence: 0.6
  4. Org-level default — fall back to a .github repo in the same org that ships an git-ape.yml, or an org variable GIT_APE_LANDING_ZONE_PROFILE. Org overrides apply only when the repo config is absent or sets mode: inherit.
  5. Auto-detection (default) — runs the heuristics above.

Precedence: chat flag > env var > repo config > org default > auto-detect.

When mode: force, skip detection entirely and just echo "Landing zone forced to alz by .azure/git-ape.yml (repo config)". When mode: disabled, echo "Landing zone detection disabled" and continue with no LZ-aware behavior.

Open design questions / options to elaborate

  • Should the skill live in .github/skills/azure-landing-zone-detector/ or be merged into /prereq-check? (Leaning: its own skill, invoked by the orchestrator and by /prereq-check summary.)
  • Which agents consume the result?
    • azure-requirements-gatherer → pre-fill region/tags/naming.
    • azure-template-generator → prefer hub-spoke peering vs. standalone VNet.
    • azure-security-analyzer → suppress findings already enforced by LZ policy.
    • azure-role-selector → pick from LZ custom roles when available.
    • azure-principal-architect → include LZ alignment in WAF review.
  • Caching: how long is a detection result valid? Invalidate on subscription change or on explicit /landing-zone refresh.
  • Multi-subscription deployments: detect per-subscription and warn on mismatch.
  • Should we ship a small catalog of known LZ profiles (ALZ, SLZ, FSI LZ, Sovereign, custom) with their fingerprints, versioned in the repo under docs/landing-zones/?
  • Sovereign/air-gapped clouds: ensure detection works against Azure Government / China endpoints.
  • Telemetry/privacy: detection reads tenant/MG metadata — ensure nothing sensitive is written to logs or committed artifacts beyond IDs already in .azure/deployments/.

Reuse from microsoft/azure-skills

Rather than reimplement detection heuristics from scratch, compose the new /azure-landing-zone-detector skill on top of existing MIT-licensed skills in microsoft/azure-skills:

  • azure-enterprise-infra-planner — LZ/hub-spoke/CAF reference patterns + WAF checklist + MCP tools (get_azure_bestpractices_get, microsoft_docs_search, bicepschema_get).
  • azure-compliance — policy assignment / initiative discovery (heuristic B).
  • azure-resource-lookup — platform resource discovery (heuristic C).
  • azure-rbac — LZ custom role detection for azure-role-selector alignment.
  • azure-diagnostics — confirm central Log Analytics / DINE wiring.

Integration options to decide:

  1. Vendor subset into .github/skills/ (tight coupling, offline-friendly).
  2. Reference via .mcp.json so Copilot agents call them as MCP tools (loose coupling, auto-updates).
  3. Hybrid: vendor the LZ detection reference data (references/), MCP-call the live probes.

Acceptance criteria

  • New skill /azure-landing-zone-detector exists under .github/skills/ with a prompt + shell helpers.
  • @git-ape invokes it in Stage 1 (Requirements) before azure-naming-research.
  • Detection produces a structured record at .azure/deployments/landing-zone.json and a user-facing chat echo.
  • Supports alz, slz, caf-custom, none, unknown with a confidence score and listed signals.
  • Honors override precedence: chat flag → env var → .azure/git-ape.yml → org .github/git-ape.yml → auto.
  • Works in both Interactive and Headless execution modes.
  • Documented in a new docs/LANDING_ZONES.md with examples of each profile and override config.
  • /prereq-check surfaces the landing-zone status line in its summary.
  • Unit-style fixture tests for detection against mocked az outputs (ALZ hierarchy, non-ALZ flat sub, SLZ).

References

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions