Skip to content

feat(azure-to-aws): add live az CLI discovery fragment - #38

Open
herosjourney wants to merge 3 commits into
icarthick:feat/azure-to-awsfrom
herosjourney:feat/azure-live-cli-discovery
Open

herosjourney wants to merge 3 commits into
icarthick:feat/azure-to-awsfrom
herosjourney:feat/azure-live-cli-discovery

Conversation

@herosjourney

Copy link
Copy Markdown

What this adds

Implements the live az CLI discovery path that discover.md already reserved a step-2 slot for ("the live az path — security contract, capture pre-work, parsing fragment, in that order") but that had not shipped. Until now a workspace with no Terraform — the common startup case — could not be inventoried at all; discover would halt.

This is meant to merge into feat/azure-to-aws (awslabs#304), not main.

How it works

discover-live.md is a two-part fragment matching the phase's execution model (the phase is _interactive: false, so a dispatched worker cannot prompt for consent):

  • Part A — main-window pre-work. The consent gate + read-only az capture run in the interactive main window, invoked from the phase's new _main_window_prework precondition. Fast-path is az resource list (one call, no extension, Reader role) plus per-service enrichment rows; output goes to $MIGRATION_DIR/live-capture/.
  • Part B — dispatched live-parse fragment. File-only, runs no az; parses live-capture/ into azure-resource-inventory.json / azure-resource-clusters.json, merging with and surfacing drift against any IaC inventory. Mirrors the RDfA split.

Because az emits canonical Microsoft.* ARM types natively, the live path is a second producer of the same inventory contract — no type-translation table. azure_type_provenance is table, source is live.

Security

Read-only command allowlist; never captures app-setting/connection-string values, Key Vault or Cognitive Services secrets, or tokens; explicit --subscription scope on every command; NAME-only --query projections; sensitive-key redaction pass.

Wiring into discover.md

  • Registers the live-parse fragment (triggers on live-capture/manifest.json).
  • Adds the Part-A _main_window_prework precondition (read-only, never a hard-stop).
  • Relaxes the completion-anchor and inventory-exists postconditions to accept live as a producer.
  • Widens the azure_type_provenance enum to the full schema set (table | derived | derived_uncorroborated | user_confirmed) and adds source to that assertion.
  • Splits the Cognitive-Services PRODUCER AGREEMENT postcondition into IaC and live-only clauses, so a live-only run does not false-fail the terraform/tf_address requirements.
  • Flips the Status section from "lands later" to landed.
  • discover-assemble.md already modeled live in its source-precedence and confidence tiers; this adds live-parse to its declared _reads and AI-signal _when.

Verification

  • Byte-identical across the advisor/ and migrate/ trees.
  • mise run drift:check (399 identical), fmt:check, lint:md (0 errors) all green.
  • Edge types/shape, source, and azure_type_provenance values validated against schema-discover-azure.md; AI detection method (live_az) and profile_source (iac_cognitive) validated against schema-discover-ai.md.

Honest scope note

This delivers the live az path only. Two SKILL.md claims are still ahead of the code and remain follow-ups (not addressed here):

  • Bicep/ARM parsing — discover-iac.md is still Terraform-only, though the SKILL.md description lists "migrate Bicep/ARM to Terraform" triggers.
  • "Live-first" ordering framing — the SKILL.md says live is "offered first"; this PR offers live when no IaC is present or the user asks to augment. The framing may want a light touch-up to match.

Live capture was validated against a real subscription (az-cli 2.90.0) for the preflight, fast-path, and the Container Apps / PostgreSQL / Storage / ACR / Log Analytics / Cognitive Services rows; the remaining service rows carry command shapes ported from the pattern and should get one live pass before broad reliance.

Logan Kleier added 3 commits September 22, 2026 14:19
Implements the live-`az` discovery path that discover.md previously reserved a
step-2 slot for but never shipped, so a workspace with no Terraform (the common
startup case) can still be inventoried.

- New `discover-live.md`: a two-part fragment matching the phase's execution model.
  Part A (main-window pre-work) runs the consent gate + read-only `az` capture
  (fast-path `az resource list` + per-service enrichment rows), writing raw JSON to
  `$MIGRATION_DIR/live-capture/`. Part B (the dispatched `live-parse` fragment) parses
  that directory into `azure-resource-inventory.json` / `azure-resource-clusters.json`,
  merging with and surfacing drift against any IaC inventory. Mirrors the RDfA split.
- Because `az` emits canonical `Microsoft.*` ARM types natively, the live path is a
  second producer of the same inventory contract with no type-translation table:
  azure_type_provenance is `table`, source is `live`.
- Security contract: read-only allowlist, never captures app-setting/connection-string
  values, Key Vault or Cognitive Services secrets, or tokens; explicit `--subscription`
  scope; NAME-only `--query` projections; sensitive-key redaction.
- Wires it into discover.md: registers the `live-parse` fragment (triggers on
  `live-capture/manifest.json`), adds the Part-A `_main_window_prework` precondition,
  relaxes the completion-anchor and inventory-exists postconditions to accept live as a
  producer, widens the azure_type_provenance enum to the full schema set, and splits the
  Cognitive-Services PRODUCER AGREEMENT postcondition into IaC and live-only clauses so a
  live-only run does not false-fail the terraform/tf_address requirements. Flips the
  Status section from "lands later" to landed.
- discover-assemble.md already modeled live in its source-precedence and confidence
  tiers; adds `live-parse` to its declared `_reads` and AI-signal `_when`.

Byte-identical across the advisor and migrate trees; drift/fmt/lint:md all green.

Note: this delivers the live-`az` path only. Bicep/ARM parsing in discover-iac.md and
the SKILL.md "live-first" ordering framing are still ahead of the code and remain
follow-ups.
The live `az` path is now real (this branch), but the SKILL.md still advertised
IaC dialects the discover-iac fragment does not yet extract. Align the copy with
what actually ships:

- Drop the "migrate Bicep to Terraform" / "migrate ARM templates to Terraform"
  triggers and reword "discover from Terraform/Bicep/ARM templates" to name
  Terraform (azurerm_*) + live `az` as the working sources, with Bicep/ARM
  explicitly "recognized but extractors not yet built."
- Fix "one IaC fragment covers Terraform, Bicep, and ARM" -> extracts Terraform
  today, Bicep/ARM planned.
- Fix "IaC (Terraform/Bicep/ARM) fully supported" in the capability list.
- Reframe "live-first ... offered first" to "offered when there is no azurerm_*
  Terraform, or to augment IaC" — matching the discover.md wiring, which offers
  live capture rather than always running it first.

Input-file and Generate-output lists are unchanged: .bicep/ARM files can still be
PRESENT (discover-iac detects them) and Generate still emits Terraform. Both plugin
copies stay byte-identical; drift/fmt/lint:md green.
…ontmatter)

The live-capture wiring introduced two frontmatter values outside the validator's
closed vocabularies, failing `mise run build` (lint:frontmatter):
- an invented `_preconditions` check kind `_main_window_prework` (allowed kinds:
  _check_phase_completed, _check_single_active_phase, _check_file_exists,
  _validate_json, _assert), and
- an `_on_failure: _continue` action (allowed: _warn_and_skip, _default_and_warn,
  _halt_and_inform, _unrecoverable).

Main-window pre-work is prose, not a structured gate check, so move it out of
`_preconditions` and into the phase body's "Run the phase" steps as a new Step 2
(interactive Part A of discover-live.md), renumbering the following steps. The
source-availability `_assert` now references that body step instead of the removed
frontmatter check. Behavior is unchanged; only the expression is now schema-valid.

Both plugin copies byte-identical; drift, fmt, lint:md, lint:types, and
lint:frontmatter all pass.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant