Skip to content

Local Testing — Azure (floci-az)

llms.txt lists every page for an agent
Optional: hand this page to your coding agentThe steps work by hand too.
Show the whole prompt
Read https://intentius.io/chant/local-testing/azure/.
In `examples/local-cloud-trio`, run `npm install` and then `npx chant run azure --no-record`. The run boots floci-az and applies the ARM template with `azApply`. It checks the storage account and then removes the container, and it needs Docker.
Keep the `endpoint` override on the local floci-az port, and show me what the run prints.
Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.

floci-az emulates Azure’s resource CRUD but not the Microsoft.Resources/deployments provider, so az deployment has nothing to talk to. azApply works around that: it reads the ARM template chant synthesizes and PUTs each resource straight to floci-az’s ARM resource endpoints, in dependency order, resolving ARM expressions from live responses as it goes.

A storage account, described as data. It synthesizes to an ARM template:

// src/azure/infra.ts — StorageAccountSecure is a composite (secure defaults)
export const { storageAccount } = StorageAccountSecure({
name: "triostore",
location: "eastus",
sku: "Standard_LRS",
tags: { project: "cross-cloud-demo" },
});

chant run azure boots floci-az, builds the ARM template, applies it with azApply, verifies the account over the ARM endpoint, and removes the container.

ops/azure.op.ts
export default Op({
name: "azure",
taskQueue: "trio-azure",
phases: [
phase("Emulator", [flociAzUp()]),
phase("Build", [build(".", { script: "build:azure" })]),
phase("Apply", [azApply("dist/azure.json", { resourceGroup: "trio-rg", location: "eastus", endpoint: "http://localhost:4577" })]),
phase("Verify", [httpCheck("http://localhost:4577/subscriptions/.../providers/Microsoft.Storage/storageAccounts/triostore?api-version=2025-06-01")]),
phase("Teardown", [flociAzDown()]),
],
});

az deployment submits a whole template to the deployments provider and lets Azure order and resolve it. floci-az has no such provider, so azApply does that work itself:

  • Reads the ARM template chant emitted and ensures the resource group exists.
  • Orders resources by their resourceId/reference references — a referenced resource applies before the one that references it — and detects cycles.
  • Evaluates ARM expressions as it applies: resourceGroup(), subscription(), concat, uniqueString, resourceId(...), plus the runtime-state functions reference('name') and listKeys(id, apiVersion), resolved from the live PUT responses of resources applied earlier in the run.
  • PUTs each resource to {endpoint}{resourceId}?api-version=... and captures the response so later resources can reference it.

This is the same evaluation a real ARM deployment performs; azApply just runs it client-side against the emulator’s resource CRUD.

Requires Docker and curl on PATH.

Terminal window
cd examples/local-cloud-trio
npm install
chant run azure

azDelete is the inverse of azApply: it reads the same template and deletes the resources it declares, in reverse dependency order (a referrer goes before what it references), idempotently.

azApply also takes prune: true for an owned-only prune — after applying, it deletes chant-managed resources of a templated type whose name is no longer in the template. chant stamps a managed-by: chant tag on everything it applies and only ever prunes tagged resources, so a foreign resource sharing the group is never touched.

Drop the endpoint override and azApply targets real Azure ARM. The template, the ordering, and the expression evaluation are unchanged — only the resource-manager host differs.

chant