Skip to content

docs(CLM hack): Ch1 local clone + venv; Ch4 deploy fail-fast (provider-register + containerapp-up) - #431

Merged
Marco Weber (qxsch) merged 8 commits into
microsoft:mainfrom
glejdis:clm-local-venv-setup
Aug 21, 2026
Merged

docs(CLM hack): Ch1 local clone + venv; Ch4 deploy fail-fast (provider-register + containerapp-up)#431
Marco Weber (qxsch) merged 8 commits into
microsoft:mainfrom
glejdis:clm-local-venv-setup

Conversation

@glejdis

@glejdis glejdisshkembi (glejdis) commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes to the Agentic Contract Lifecycle Management hack (03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/), from running it with live participants.

1 · Migrate Challenge 1 setup: Dev Container / Codespaces → local clone + venv

  • Challenge 1 brief & walkthrough (challenges/challenge-01.md, walkthrough/challenge-01/solution-01.md): clone the repo, open it in VS Code, then python -m venv .venv → activate → pip install -r src/requirements.txt, and Python: Select Interpreter → .venv. Notes the PEP 668 externally-managed-environment error a venv avoids on Python 3.12+.
  • Endpoint screenshots: added endpoint-foundry-project.png and endpoint-azure-search.png with a "where to copy the two endpoints from" section in solution-01 (Foundry Project endpoint and Azure AI Search Url).
  • Removed the hack-scoped .devcontainer/ and the two Codespace step images (02-create-codespace.png, 03-codespace-ready.png).
  • Swept stray Codespaces/devcontainer mentions across README.md, src/, docs/coach-guide.md, labautomation/, deploy/mcp-server/, and challenge-04.md — comment/label-only. The labautomation/deploy-lab.ps1 platform parameter block is untouched.

2 · Fix Challenge 4 deploy: provider-register AuthorizationFailed aborts the deploy

The MCP-server deploy scripts ran az provider register --namespace Microsoft.App / Microsoft.OperationalInsights, a subscription-scope action. In a resource-group lab the participant only owns the RG, so it fails with AuthorizationFailed — and under PowerShell 5.1 with $ErrorActionPreference=Stop, az's stderr becomes a terminating error that aborts the whole deploy, even though the platform already registered those providers.

  • deploy/mcp-server/deploy.ps1 / deploy.sh: query registrationState and only register when actually needed; relax error handling so the best-effort call can never abort the deploy.
  • challenges/challenge-04.md / walkthrough/challenge-04/solution-04.md: document that the AuthorizationFailed on provider register is harmless and now skipped.

3 · Fix Challenge 4 deploy: fail fast on the az containerapp up cloud-build bug

az containerapp up --source crashes on Azure CLI core 2.86.0 with 'NoneType' object has no attribute 'linux' in queue_acr_build — a known CLI regression (Azure/azure-cli#33369, fixed in 2.87.0+) where the cloud image-build path resolves the OS/Architecture SDK models from the wrong package. In the PowerShell script that failure did not stop execution, so it cascaded into misleading containerapp 'clm-mcp' does not exist and --assignee-object-id: expected one argument errors that hid the real cause.

  • deploy/mcp-server/deploy.ps1 / deploy.sh: capture the exit code of az containerapp up and stop with an actionable message (run az upgrade, need >= 2.87.0) instead of cascading into the identity/role steps.
  • challenges/challenge-04.md / walkthrough/challenge-04/solution-04.md: troubleshooting rows for the bug (fix is az upgrade on the participant's machine; partial ACR/env are reused on re-run).

4 · Fix Challenge 4 deploy: find .env in src/ too (not only repo root)

The deploy scripts only looked for a repo-root .env. Participants who copy src/.env.example in place keep their .env in src/ (the CWD their agents run from), so a zero-arg ./deploy.ps1 threw AZURE_AI_PROJECT_ENDPOINT is not set unless they remembered -EnvFile.

  • deploy/mcp-server/deploy.ps1 / deploy.sh: resolve the env file as repo-root .env first, then src/.env; an explicit -EnvFile / ENV_FILE still wins. src/.env is already excluded from the image build context by src/.dockerignore, so this is safe. Clearer "endpoint not set" message.
  • challenges/challenge-04.md / walkthrough/challenge-04/solution-04.md: troubleshooting rows for the error.

Scope is limited to files under the hack directory; no workflow or platform files are changed.

5 · Fix Challenge 4 deploy: auto-heal a stuck Container Apps environment

After the CLI upgrade (section 3) the ACR build succeeds, but the earlier crashed runs can leave the Container Apps managed environment (auto-named <app>-env = clm-mcp-env) stuck in a non-Succeeded state. az containerapp up reuses that env by name, so every re-run then fails with ManagedEnvironmentNotProvisioned — cascading again into clm-mcp does not exist and the empty-principalId role error.

  • deploy/mcp-server/deploy.ps1 / deploy.sh: before az containerapp up, query the env's provisioningState and delete it when it is not Succeeded so up recreates it cleanly. Generalized the post-up failure hint to cover both the CLI 2.86.0 bug and ManagedEnvironmentNotProvisioned, and guard the role step when principalId is empty.
  • challenges/challenge-04.md / walkthrough/challenge-04/solution-04.md: troubleshooting row (delete clm-mcp-env and re-run; if a fresh env also fails it is usually region capacity — try westeurope).

6 · Fix Challenge 4 deploy: assign the Foundry role by GUID (Azure AI UserFoundry User rename)

The very last deploy step — granting the container's managed identity access to Foundry — failed with Role 'Azure AI User' doesn't exist. even though the app had already been created and deployed. The built-in role "Azure AI User" was renamed to "Foundry User", so az ... --role "Azure AI User" (by display name) no longer resolves — but the role-definition GUID 53ca6127-db72-4b80-b1b0-d745d6d5456d is unchanged. (Confirmed: az role definition list --name "Azure AI User" returns empty; --name "Foundry User" returns that GUID.)

  • deploy/mcp-server/deploy.ps1 / deploy.sh: assign the role by GUID first, then fall back to Cognitive Services User / Cognitive Services OpenAI User by name; treat an already-existing assignment as success; never let a failed attempt abort the run. The grant it yourself hint now uses the GUID.
  • challenges/challenge-04.md / walkthrough/challenge-04/solution-04.md: troubleshooting row for the rename, and the 401/403 rows now cite the GUID.

7 · Challenge 5: pre-register Microsoft.BotService for the Teams publish

Publishing the agent to Teams / M365 Copilot (Challenge 5) auto-creates an Azure Bot, which needs the Microsoft.BotService resource provider registered on the subscription. The platform pre-registers Microsoft.App / Microsoft.OperationalInsights but not this one, so the Azure bot services dropdown failed with MissingSubscriptionRegistration / "The subscription is not registered to use namespace 'Microsoft.BotService'" (409). In a resourcegroup lab the participant only holds RG-Owner and cannot register a subscription-scope provider themselves.

  • labautomation/deploy-lab.ps1: best-effort Register-AzResourceProvider -ProviderNamespace Microsoft.BotService (idempotent, subscription-wide, non-fatal) so it's ready long before teams reach Challenge 5; a clear [WARN] with the manual command if the provisioning identity lacks subscription rights. The platform param contract is untouched.
  • challenges/challenge-05.md / walkthrough/challenge-05/solution-05.md: corrected the guidance — an RG-scoped participant can't self-register; a subscription Owner runs az provider register --namespace Microsoft.BotService once (unblocks every lab in the subscription). Added a troubleshooting row for the 409.

8. Challenge 5: register Microsoft.BotService via shared-deploy-lab.ps1 (self-service, no isolation downgrade)

Symptom. Challenge 5 "Publish to Teams / M365 Copilot" auto-creates an Azure Bot. In the Foundry publish dialog the Azure bot services dropdown returned a 409 MissingSubscriptionRegistration"The subscription is not registered to use namespace Microsoft.BotService." A participant then ran az provider register --namespace Microsoft.BotService and got AuthorizationFailed: in a resourcegroup lab the participant holds only subscription-Reader (+ RG-Owner), and provider registration is a subscription-scope write — so no lab account can self-register it.

Root cause. The platform pre-registers Microsoft.App / Microsoft.OperationalInsights but not Microsoft.BotService, and resourcegroup participants have no path to register a provider themselves.

Fix — the platform-sanctioned once-per-subscription hook. Added labautomation/shared-deploy-lab.ps1, which the platform runs once per subscription, before the per-participant deploy-lab.ps1 fan-out — the README's named home for "registering resource providers." It registers Microsoft.BotService once per subscription, best-effort (try/catch + [WARN], never throws, so a registration hiccup can never block provisioning of Challenges 1-4).

Why not switch deploymentType? resourcegroup-with-subscriptionowner would make every one of the up-to-labsPerSubscription (8) participants sharing a subscription an Owner of that subscription — able to see and delete each other's resource groups. The shared hook keeps deploymentType: resourcegroup, so participants stay subscription-Reader + RG-Owner and lab isolation is preserved.

Files.

  • labautomation/shared-deploy-lab.ps1new once-per-subscription hook (exact platform param contract) registering Microsoft.BotService.
  • labautomation/deploy-lab.ps1 — removed the redundant inline registration (in resourcegroup it ran as sub-Reader and would only ever [WARN], and per-lab jobs would race); points to the shared hook.
  • labautomation/lab-defaults.json — added estimatedSharedDeploymentDailyCostsUsd: 0.0 (registration is free) to document the shared hook.
  • challenges/challenge-05.md / walkthrough/challenge-05/solution-05.mdMicrosoft.BotService is now pre-registered once per subscription; the manual az provider register is documented only as a subscription-Owner fallback (an RG-scoped participant can't run it).
  • .github/instructions/labautomation.instructions.md — documented the shared-hook parameter contract and why provider registration belongs there, not in deploy-lab.ps1.

Switch the Contract Lifecycle Management hack's Challenge 1 from the
Dev Container / GitHub Codespaces flow to a local clone + Python
virtual environment flow, and drop the now-unused dev container.

- challenge-01.md / solution-01.md: clone + open in VS Code, then
  `python -m venv .venv`, activate, `pip install -r src/requirements.txt`,
  and VS Code "Python: Select Interpreter -> .venv"; note the PEP 668
  externally-managed-environment error a venv avoids on Python 3.12+.
- Add the two endpoint screenshots (Foundry Project endpoint and Azure
  AI Search Url) with a "where to copy them from" section in solution-01.
- Remove the hack-scoped .devcontainer/ and the two Codespace step
  images; sweep stray Codespaces/devcontainer mentions from README,
  src, docs, labautomation, deploy, and challenge-04.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
az provider register (Microsoft.App / Microsoft.OperationalInsights) is a
SUBSCRIPTION-scope action; in a resource-group lab the user only owns the RG,
so it fails with AuthorizationFailed. Under PowerShell 5.1 with
$ErrorActionPreference=Stop that stderr becomes a terminating error and aborts
the deploy even though the platform already registered the providers.

- deploy.ps1 / deploy.sh: check registrationState and only register when
  needed; relax EAP so the best-effort call can never abort the deploy.
- challenge-04.md / solution-04.md: document the AuthorizationFailed is
  harmless and now skipped.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
@glejdis glejdisshkembi (glejdis) changed the title docs(CLM hack): migrate Challenge 1 to local clone + venv setup docs(CLM hack): migrate Challenge 1 to local clone + venv; fix Ch4 provider-register auth failure Aug 21, 2026
az containerapp up --source cloud build crashes on Azure CLI core 2.86.0
with 'NoneType' object has no attribute 'linux' in queue_acr_build
(Azure/azure-cli#33369, fixed in 2.87.0+). The PS deploy script did not
stop on that failure, so it cascaded into misleading 'does not exist' /
'--assignee-object-id: expected one argument' errors.

- deploy.ps1 / deploy.sh: check the exit code of az containerapp up and
  stop with an actionable message (run az upgrade, need >= 2.87.0).
- challenge-04.md / solution-04.md: troubleshooting rows for the bug.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
@glejdis glejdisshkembi (glejdis) changed the title docs(CLM hack): migrate Challenge 1 to local clone + venv; fix Ch4 provider-register auth failure docs(CLM hack): Ch1 local clone + venv; Ch4 deploy fail-fast (provider-register + containerapp-up) Aug 21, 2026
… absent

deploy.ps1/.sh only looked for a repo-root .env, so participants who keep
their .env in src/ (next to .env.example, where the agents run from) hit
'AZURE_AI_PROJECT_ENDPOINT is not set' unless they passed -EnvFile.

- deploy.ps1 / deploy.sh: resolve env file as repo-root .env first, then
  src/.env; explicit -EnvFile / ENV_FILE still wins. src/.env is already
  excluded from the image build context by src/.dockerignore.
- Clearer 'endpoint not set' message + troubleshooting rows in the docs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
A Container Apps managed environment left in a non-Succeeded state by an
earlier crashed run makes every re-run of 'az containerapp up' fail with
ManagedEnvironmentNotProvisioned (it reuses the '<app>-env' env by name),
cascading into 'clm-mcp does not exist' and the empty-principalId role error.

- deploy.ps1 / deploy.sh: before 'az containerapp up', delete the
  '<app>-env' env when its provisioningState is not Succeeded, so 'up'
  recreates it cleanly. Generalize the failure hint to cover both the CLI
  2.86.0 bug and ManagedEnvironmentNotProvisioned, and guard the role step
  when principalId is empty.
- challenge-04.md / solution-04.md: troubleshooting rows for the env
  provisioning failure.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
… Foundry User rename)

The final deploy step failed with Role 'Azure AI User' doesn't exist. even though the
app was already created. The built-in role "Azure AI User" was renamed to "Foundry User";
its display name no longer resolves via 'az ... --role "Azure AI User"', but the
role-definition GUID (53ca6127-db72-4b80-b1b0-d745d6d5456d) is unchanged.

- deploy.ps1 / deploy.sh: assign the role by GUID first, then fall back to
  'Cognitive Services User' and 'Cognitive Services OpenAI User' by name; treat an existing
  assignment as success; don't let a failed try abort the run.
- challenge-04.md / solution-04.md: troubleshooting row for the rename; 401/403 rows cite the GUID.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
Publishing the agent to Teams/M365 Copilot auto-creates an Azure Bot, which needs the
Microsoft.BotService resource provider registered on the SUBSCRIPTION. The platform
pre-registers Microsoft.App / Microsoft.OperationalInsights but not this one, so the
'Azure bot services' dropdown failed with MissingSubscriptionRegistration (409). In a
resourcegroup lab the participant only holds RG-Owner and cannot register a
subscription-scope provider themselves.

- labautomation/deploy-lab.ps1: best-effort Register-AzResourceProvider for
  Microsoft.BotService (idempotent, subscription-wide, non-fatal). Param contract untouched.
- challenge-05.md / solution-05.md: an RG-scoped participant can't self-register; a
  subscription Owner runs it once. Added a troubleshooting row for the 409.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
Add the platform's once-per-subscription hook (shared-deploy-lab.ps1) to register
the Microsoft.BotService resource provider that Challenge 5's Teams / M365 publish
needs. In a resourcegroup lab the participant is only subscription-Reader (+ RG-Owner)
and cannot self-register it; the shared hook runs before the labs with subscription
rights and registers it once per subscription, best-effort (never throws, so it can
never block Challenges 1-4). Keeps deploymentType=resourcegroup so participants keep
RG isolation (vs resourcegroup-with-subscriptionowner, which would make all 8 labs
sharing a subscription Owners of it). Drops the redundant inline registration from
deploy-lab.ps1 and updates Challenge 5 docs + the labautomation instructions.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 47fea2b8-adc4-49b2-8c83-64d04bc5f28f
@qxsch
Marco Weber (qxsch) merged commit 8b7a1af into microsoft:main Aug 21, 2026
2 checks passed
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.

2 participants