From e0b30b5de374e836b89ccc5e00ea22a36d70debc Mon Sep 17 00:00:00 2001 From: Glejdis Shkembi Date: Wed, 19 Aug 2026 15:35:21 +0200 Subject: [PATCH 1/7] Remove LICENSE, SECURITY.md, SUPPORT.md, CODE_OF_CONDUCT.md from CLM agentic hack Mirrors the change made in glejdis/microhack-aiagents. These duplicate community-health files are already provided at the microsoft/MicroHack repo root, so they are redundant inside the hack folder. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../CODE_OF_CONDUCT.md | 10 --------- .../LICENSE | 21 ------------------- .../SECURITY.md | 14 ------------- .../SUPPORT.md | 18 ---------------- 4 files changed, 63 deletions(-) delete mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/CODE_OF_CONDUCT.md delete mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/LICENSE delete mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SECURITY.md delete mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SUPPORT.md diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/CODE_OF_CONDUCT.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/CODE_OF_CONDUCT.md deleted file mode 100644 index 686e5e7a0..000000000 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,10 +0,0 @@ -# Microsoft Open Source Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). - -Resources: - -- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) -- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns -- Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/LICENSE b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/LICENSE deleted file mode 100644 index cf7bcb2ba..000000000 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2026 Microsoft Corporation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SECURITY.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SECURITY.md deleted file mode 100644 index 656f79188..000000000 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SECURITY.md +++ /dev/null @@ -1,14 +0,0 @@ - - -## Security - -Microsoft takes the security of our software products and services seriously, which -includes all source code repositories in our GitHub organizations. - -**Please do not report security vulnerabilities through public GitHub issues.** - -For security reporting information, locations, contact information, and policies, -please review the latest guidance for Microsoft repositories at -[https://aka.ms/SECURITY.md](https://aka.ms/SECURITY.md). - - diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SUPPORT.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SUPPORT.md deleted file mode 100644 index 0cd2ae59f..000000000 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/SUPPORT.md +++ /dev/null @@ -1,18 +0,0 @@ -# Support - -## How to file issues and get help - -This project uses **GitHub Issues** to track bugs and feature requests. Please search the -existing issues before filing new ones to avoid duplicates. For a new issue, file your bug or -feature request as a new Issue. - -For help and questions about running this hackathon: - -- Read the top-level [README](README.md) and the per-challenge `README.md` files β€” each has a - **πŸ› οΈ Troubleshooting** section covering the most common blockers. -- If you're running this as a facilitated event, ask your **hack coach** first. -- Otherwise, open a **GitHub Issue** in this repository and tag it `question`. - -## Microsoft Support Policy - -Support for this hackathon content is limited to the resources listed above. From 3c28abccf32a5a072922dadb8711e0c9155d7812 Mon Sep 17 00:00:00 2001 From: Glejdis Shkembi Date: Wed, 19 Aug 2026 15:41:41 +0200 Subject: [PATCH 2/7] Set estimatedDailyCostsUsd to 15.0 in lab-defaults.json Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../labautomation/lab-defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json index 3c1443a4c..59ca43064 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json @@ -4,5 +4,5 @@ "deploymentType": "resourcegroup", "labsPerSubscription": 8, "preferredLocation": "swedencentral, westeurope, norwayeast", - "estimatedDailyCostsUsd": 5.0 + "estimatedDailyCostsUsd": 15.0 } From 9cec644fe47aa8e86e014a3473b6c98cc7889567 Mon Sep 17 00:00:00 2001 From: glejdisshkembi <53597226+glejdis@users.noreply.github.com> Date: Wed, 19 Aug 2026 15:50:41 +0200 Subject: [PATCH 3/7] Update preferredLocation regions in lab-defaults.json (swedencentral, norwayeast, spaincentral) --- .../labautomation/lab-defaults.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json index 59ca43064..866701b15 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/lab-defaults.json @@ -3,6 +3,6 @@ "groups": ["M365-E5-Users"], "deploymentType": "resourcegroup", "labsPerSubscription": 8, - "preferredLocation": "swedencentral, westeurope, norwayeast", + "preferredLocation": "swedencentral, norwayeast, spaincentral", "estimatedDailyCostsUsd": 15.0 } From 16472f19ea73452d873fc536499a2d70da1d2167 Mon Sep 17 00:00:00 2001 From: Glejdis Shkembi Date: Wed, 19 Aug 2026 15:51:46 +0200 Subject: [PATCH 4/7] docs(challenge-01): make local VS Code the primary setup path, Codespaces optional Mirrors glejdis/microhack-aiagents: Task 1 now leads with clone + Dev Containers in VS Code; GitHub Codespaces moved to an optional note. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../challenges/challenge-01.md | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md index f55209e12..ee43595c5 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md @@ -5,7 +5,7 @@ Welcome to your very first challenge! Here you lay the foundation for the whole microhack: you'll deploy the Azure resources, wire up your development environment, and seed the contract corpus the later challenges build on. By the end you'll have the full **Microsoft Foundry** environment -running β€” with **zero local install** β€” so the rest of the hack is pure agent-building. +running in a **prebuilt dev container** β€” so the rest of the hack is pure agent-building. If something isn't working as expected, please let your coach know. @@ -13,8 +13,8 @@ If something isn't working as expected, please let your coach know. > **πŸ“‹ Prerequisites:** > - An **Azure subscription** your lab was provisioned in *(or, if self-hosting, one with rights to create a Foundry project and deploy GPT models)*. -> - A **GitHub account** (to open the repo in Codespaces). -> - **GitHub Codespaces** access β€” everything runs in the browser; no local tooling required. +> - A **GitHub account** (to clone the repo). +> - **VS Code** with the **Dev Containers** extension and **Docker Desktop** β€” the repo's dev container has everything preinstalled *(or **GitHub Codespaces**, if you'd rather run in the browser)*. > 🧩 **How to use this challenge:** for a MicroHack event your Azure resources are **provisioned for > you** β€” you just point your `.env` at them (Task 3) and **confirm you understand what got created**: @@ -30,8 +30,8 @@ If something isn't working as expected, please let your coach know. ## 🧭 Context -Everything runs from **GitHub Codespaces** using the devcontainer in this repo (Python 3.11, Azure -CLI, `azd`, Node). For a MicroHack event the resources below are **already provisioned** into **one +Everything runs inside the **dev container** in this repo (Python 3.11, Azure +CLI, `azd`, Node) β€” open it locally in **VS Code** (Dev Containers) or in **GitHub Codespaces**. For a MicroHack event the resources below are **already provisioned** into **one resource group** and their endpoints appear on your **lab dashboard**; you copy them into `.env` in Task 3. *(Self-hosting? One **`azd up`** β€” Bicep in [`infra/`](../labautomation/infra/) β€” provisions the same resource group and autofills `.env`.)* @@ -133,31 +133,33 @@ text at crawl time); regenerate the PDFs with `python src/scripts/make_corpus_pd - [ ] *(Self-hosting only)* Your Azure subscription can deploy **GPT** models (ask your coach if unsure). - [ ] You have ~30 minutes and a stable connection (provisioning takes 5–10 min on its own). -### Task 1 Β· Open the Codespace (~7 min) +### Task 1 Β· Open the project in VS Code (~7 min) -**No fork needed for the main hack (Challenges 1–5)** β€” the code you run lives in this repo. Open it in **GitHub Codespaces** (a full VS -Code + terminal in your browser, zero local install); because you work off the source repo, `git pull` +**No fork needed for the main hack (Challenges 1–5)** β€” the code you run lives in this repo. Clone it and open it in **VS +Code** using the **Dev Containers** extension (a prebuilt container with Python, Azure CLI, `azd`, and Node β€” no manual installs); because you work off the source repo, `git pull` always gets the latest fixes. *(The **one exception** is the optional **Challenge 6** CI bonus β€” it runs in **GitHub Actions**, so it needs **your own fork**; you'll create it there, not now.)* -1. On the repo's GitHub page, click **`< > Code` β†’ Codespaces β†’ Create codespace on `main`**. - *(Prefer local? `git clone` the repo and **Reopen in Container** with the VS Code Dev Containers - extension.)* +1. `git clone` this repo, then open the folder in **VS Code** (e.g. `code microhack-aiagents`). When VS + Code prompts **"Reopen in Container"**, click it β€” or run **Dev Containers: Reopen in Container** from + the Command Palette (**F1**). Requires the **Dev Containers** extension and **Docker Desktop**. 2. Wait for the container to build β€” it installs dependencies with `pip install -r requirements.txt` automatically. When the terminal stops scrolling and shows a prompt, it's ready. -GitHub Β· Code β†’ Codespaces β†’ Create codespace on main - -βœ… **You'll know it worked when:** a browser VS Code editor opens with a **Terminal** panel showing a +βœ… **You'll know it worked when:** a **VS Code** window opens (locally or in the browser) with a **Terminal** panel showing a ready prompt (e.g. `@your-username ➜ /workspaces/microhack-aiagents (main) $`). > [!NOTE] -> If Codespaces isn't enabled in your org, see [enabling Codespaces](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/enabling-or-disabling-github-codespaces-for-your-organization) or use a [free personal account](https://github.com/signup) (120 core-hours/month free). While it builds, skim the [scenario & architecture](../README.md#the-scenario--contoso-global) so the pieces you deploy here make sense. +> **Prefer the browser? Use GitHub Codespaces instead.** On the repo's GitHub page, click **`< > Code` β†’ Codespaces β†’ Create codespace on `main`** β€” the same dev container builds in the cloud, so you need no local Docker. If Codespaces isn't enabled in your org, see [enabling Codespaces](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/enabling-or-disabling-github-codespaces-for-your-organization) or use a [free personal account](https://github.com/signup) (120 core-hours/month free). +> +> GitHub Β· Code β†’ Codespaces β†’ Create codespace on main +> +> While it builds, skim the [scenario & architecture](../README.md#the-scenario--contoso-global) so the pieces you deploy here make sense. --- ### Task 2 Β· Log in to Azure (~3 min) -Now connect the terminal to your Azure account. In the Codespace **Terminal**, type this and press Enter: +Now connect the terminal to your Azure account. In the **VS Code Terminal**, type this and press Enter: ```bash az login --use-device-code @@ -198,13 +200,13 @@ For a **MicroHack event your Azure resources are already provisioned** β€” a res Foundry project, the three-model GPT fleet, and Azure AI Search. You don't deploy anything; you just point your `.env` at them using the values on your **lab dashboard**. -**Step 3a β€” create your `.env`** from the template (Codespace terminal, at the repo root): +**Step 3a β€” create your `.env`** from the template (VS Code terminal, at the repo root): ```bash cp src/.env.example .env ``` -**Step 3b β€” copy your dashboard values into `.env`.** Open `.env` in the Codespace editor and fill in +**Step 3b β€” copy your dashboard values into `.env`.** Open `.env` in the VS Code editor and fill in the values shown on your lab dashboard: | Lab dashboard credential | `.env` variable | Example value | @@ -257,7 +259,7 @@ It provisions for **5–10 minutes**, assigns the RBAC roles the later challenge grounding with `azd env set DEPLOY_BING true` before `azd up`. > **Prefer not to use `azd`?** `LOCATION=swedencentral ./labautomation/deploy.sh` (add `--with-sql` / -> `--with-bing`; on Windows outside Codespaces use `./labautomation/deploy.ps1`) provisions the same +> `--with-bing`; on native **Windows** use `./labautomation/deploy.ps1`) provisions the same > resources and writes `.env` too. If it fails with `DeploymentModelNotSupported`, a model/version > isn't offered in your region β€” see [πŸ› οΈ Troubleshooting](#️-troubleshooting). @@ -286,7 +288,7 @@ your **`clm-project`** β†’ **Models + endpoints**. Confirm the deployments show > > Screenshot slot: model deployments -**4c β€” Your `.env` file.** In the Codespace file explorer, open **`.env`** at the repo root. Confirm the +**4c β€” Your `.env` file.** In the VS Code file explorer, open **`.env`** at the repo root. Confirm the values are filled in (every entry has a value **except** the `SHAREPOINT_*` corpus and the Challenge 5 `MICROSOFT_APP_*` / `TEAMS_*` variables, which you fill later). @@ -604,7 +606,7 @@ Smoke test: βœ… PASS | `Project can only be created under AIServices Kind account with allowProjectManagement set to true` | Fixed in the template (`account.properties.allowProjectManagement: true`). If you hit it, your checkout is behind β€” run `git pull` and redeploy. | | SharePoint: *"Tenant does not have a SPO license"*, or you can't grant the app's Graph **admin consent** (only Global Reader / **"Grant admin consent" greyed out**) | Only happens if you're **not** an admin of the tenant β€” in your own sandbox tenant the Path A script self-grants consent. If you hit it, it's **not** a failure: use the **local-PDF fallback (Path B)** β€” leave the `SHAREPOINT_*` values blank in `.env` and run `python src/scripts/seed_corpus.py`. It extracts `src/data/**/*.pdf` and populates `clm-corpus` directly (needs the Search Index Data Contributor role, granted during provisioning) β€” the **same index** the SharePoint path builds, so Challenges 2–6 are unaffected. See [Task 5, Path B](#task-5--seed-the-corpus). | | `account project create` unavailable | The CLI project command is preview. Create the project in the **Foundry portal**, then set `AZURE_AI_PROJECT_ENDPOINT` in `.env` manually (Overview β†’ Endpoint). | -| `az login` in Codespaces | Use `az login --use-device-code`. | +| `az login` in a dev container / Codespaces | Use `az login --use-device-code`. | | Search / quota errors | Ensure the subscription has quota for Basic Search + the model SKUs; request quota if needed. | | `PermissionDenied` after deploy | RBAC can take 5–10 min to propagate. Wait, run `az login --use-device-code` again, and retry. | From bb714804a975a18cea1cf84a63e6b5d526b06ba0 Mon Sep 17 00:00:00 2001 From: glejdisshkembi <53597226+glejdis@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:01:20 +0200 Subject: [PATCH 5/7] Hide Codespaces screenshot in challenge-01 Task 1 note --- .../challenges/challenge-01.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md index ee43595c5..103b92cea 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md @@ -151,8 +151,6 @@ ready prompt (e.g. `@your-username ➜ /workspaces/microhack-aiagents (main) $`) > [!NOTE] > **Prefer the browser? Use GitHub Codespaces instead.** On the repo's GitHub page, click **`< > Code` β†’ Codespaces β†’ Create codespace on `main`** β€” the same dev container builds in the cloud, so you need no local Docker. If Codespaces isn't enabled in your org, see [enabling Codespaces](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/enabling-or-disabling-github-codespaces-for-your-organization) or use a [free personal account](https://github.com/signup) (120 core-hours/month free). > -> GitHub Β· Code β†’ Codespaces β†’ Create codespace on main -> > While it builds, skim the [scenario & architecture](../README.md#the-scenario--contoso-global) so the pieces you deploy here make sense. --- From f310fa2ed362ccb7b8d10c653655a9199b7b2ae0 Mon Sep 17 00:00:00 2001 From: Glejdis Shkembi Date: Wed, 19 Aug 2026 16:27:03 +0200 Subject: [PATCH 6/7] Move azd/Docker/git config files into src/ Relocate azure.yaml, Dockerfile, .dockerignore, .gitignore, .gitattributes, and requirements.txt into src/ and update all references so azd, the container build, CI, and docs still work. - azd is now run from src/ (cd src && azd up); azure.yaml infra.path and postprovision hook paths adjusted accordingly. - Docker build context is now src/; deploy scripts use --source src and .dockerignore rewritten for the src/ context. - write_env.py and setup_sharepoint_corpus.py run azd with cwd=src/. - CI, devcontainer, and all docs/challenges/walkthroughs updated. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1ad09303-8cf2-472e-bfa3-04af5233d633 --- .../.devcontainer/devcontainer.json | 2 +- .../.dockerignore | 12 ------------ .../.github/workflows/ci-eval.yml | 2 +- .../README.md | 12 +++++++----- .../challenges/challenge-01.md | 10 +++++----- .../challenges/challenge-04.md | 6 +++--- .../deploy/mcp-server/README.md | 2 +- .../deploy/mcp-server/deploy.ps1 | 4 ++-- .../deploy/mcp-server/deploy.sh | 6 +++--- .../docs/coach-guide.md | 2 +- .../labautomation/README.md | 4 ++-- .../src/.dockerignore | 18 ++++++++++++++++++ .../{ => src}/.gitattributes | 0 .../{ => src}/.gitignore | 2 +- .../{ => src}/Dockerfile | 11 +++++++---- .../src/README.md | 4 ++-- .../{ => src}/azure.yaml | 11 ++++++----- .../src/clm_common/documents.py | 2 +- .../src/red_team.py | 2 +- .../{ => src}/requirements.txt | 0 .../src/scripts/make_step_placeholders.py | 2 +- .../src/scripts/setup_sharepoint_corpus.py | 5 +++-- .../src/scripts/write_env.py | 12 +++++++----- .../walkthrough/challenge-01/solution-01.md | 5 +++-- .../walkthrough/challenge-04/solution-04.md | 8 ++++---- 25 files changed, 80 insertions(+), 64 deletions(-) delete mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.dockerignore create mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.dockerignore rename 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/{ => src}/.gitattributes (100%) rename 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/{ => src}/.gitignore (95%) rename 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/{ => src}/Dockerfile (78%) rename 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/{ => src}/azure.yaml (68%) rename 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/{ => src}/requirements.txt (100%) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json index c0ab20546..9ed6ddf9d 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json @@ -9,7 +9,7 @@ }, "ghcr.io/devcontainers/features/github-cli:1": {} }, - "postCreateCommand": "pip install --upgrade pip && pip install -r requirements.txt", + "postCreateCommand": "pip install --upgrade pip && pip install -r src/requirements.txt", "customizations": { "vscode": { "extensions": [ diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.dockerignore b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.dockerignore deleted file mode 100644 index f4d6e7c1c..000000000 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.dockerignore +++ /dev/null @@ -1,12 +0,0 @@ -# Keep the MCP server image build context minimal β€” only requirements.txt and -# src/ are needed to run the server. Everything else (docs, images, walkthrough, -# lab automation, screenshots) is excluded. -* -!requirements.txt -!src - -# Prune noise re-included with src/ -**/__pycache__ -**/*.pyc -**/*.pyo -**/.pytest_cache diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.github/workflows/ci-eval.yml b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.github/workflows/ci-eval.yml index 7adda2df5..4785fa3ca 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.github/workflows/ci-eval.yml +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.github/workflows/ci-eval.yml @@ -45,7 +45,7 @@ jobs: - name: Install dependencies if: steps.guard.outputs.configured == 'true' - run: pip install -r requirements.txt "azure-ai-evaluation[redteam]" + run: pip install -r src/requirements.txt "azure-ai-evaluation[redteam]" - name: Azure login (OIDC) if: steps.guard.outputs.configured == 'true' diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/README.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/README.md index 39304f5de..04660f1c4 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/README.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/README.md @@ -300,10 +300,10 @@ challenges are a single story: ## Getting started 1. **Open this repo in Codespaces** (no fork needed β€” the optional Challenge 6 CI bonus is the only part that needs a fork) β€” **Code β†’ Codespaces β†’ Create codespace**. The devcontainer installs - Python 3.11, Azure CLI, `azd`, Node, and `requirements.txt` automatically. + Python 3.11, Azure CLI, `azd`, Node, and `src/requirements.txt` automatically. 2. `az login` (and `azd auth login` if you use the `azd up` path) 3. Do **[Challenge 1](challenges/challenge-01.md)** to deploy resources and seed the corpus β€” provision with - **`azd up`** (Bicep in `labautomation/infra/`), the **`labautomation/deploy`** script, or the one-click + **`azd up`** (run from `src/`; Bicep in `labautomation/infra/`), the **`labautomation/deploy`** script, or the one-click **Deploy to Azure** button (`infra/azuredeploy.json`). The first two autofill your `.env`. - **Seeding the corpus β€” default is Path B** (Challenge 1 Β· Task 6): **Path B (local-PDF)** needs no SharePoint and no admin consent, works in every tenant, and builds the `clm-corpus` index β€” @@ -317,12 +317,14 @@ challenges are a single story: ``` . -β”œβ”€β”€ .devcontainer/ # Codespaces definition -β”œβ”€β”€ azure.yaml # azd config (points at labautomation/infra, write-.env hook) +β”œβ”€β”€ .devcontainer/ # Codespaces / Dev Containers definition β”œβ”€β”€ README.md # this file β”œβ”€β”€ challenges/ # challenge-01 … challenge-06 (one markdown brief per challenge) β”œβ”€β”€ walkthrough/ # challenge-0N/solution-0N.md β€” reference solution per challenge -β”œβ”€β”€ src/ # all source code: agents/, clm_common/, mcp_server/, data/, scripts/ … +β”œβ”€β”€ src/ # all source code + build/config: agents/, clm_common/, mcp_server/, data/, scripts/ … +β”‚ β”œβ”€β”€ azure.yaml # azd config (points at ../labautomation/infra, write-.env hook) β€” run `cd src && azd up` +β”‚ β”œβ”€β”€ Dockerfile # Challenge 4 MCP server image (.dockerignore alongside; build context = src/) +β”‚ β”œβ”€β”€ requirements.txt # Python dependencies β”‚ └── data/ # CLM corpus (PDF contracts/templates/clauses/policies) + eval datasets β”œβ”€β”€ labautomation/ # infra (Bicep) + deploy, seed corpus/SQL, write .env, smoke test β”œβ”€β”€ images/ # rendered images + per-challenge screenshots + diagrams diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md index 103b92cea..c5627509e 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-01.md @@ -128,7 +128,6 @@ text at crawl time); regenerate the PDFs with `python src/scripts/make_corpus_pd **Before you begin β€” tick these off:** -- [ ] You can sign in to [github.com](https://github.com). - [ ] You can sign in to the [Azure Portal](https://portal.azure.com) with the account your lab was provisioned for (or, if self-hosting, one that can **create resources**). - [ ] *(Self-hosting only)* Your Azure subscription can deploy **GPT** models (ask your coach if unsure). - [ ] You have ~30 minutes and a stable connection (provisioning takes 5–10 min on its own). @@ -139,17 +138,17 @@ text at crawl time); regenerate the PDFs with `python src/scripts/make_corpus_pd Code** using the **Dev Containers** extension (a prebuilt container with Python, Azure CLI, `azd`, and Node β€” no manual installs); because you work off the source repo, `git pull` always gets the latest fixes. *(The **one exception** is the optional **Challenge 6** CI bonus β€” it runs in **GitHub Actions**, so it needs **your own fork**; you'll create it there, not now.)* -1. `git clone` this repo, then open the folder in **VS Code** (e.g. `code microhack-aiagents`). When VS +1. Open the folder in **VS Code** (e.g. `code microhack-aiagents`). When VS Code prompts **"Reopen in Container"**, click it β€” or run **Dev Containers: Reopen in Container** from the Command Palette (**F1**). Requires the **Dev Containers** extension and **Docker Desktop**. -2. Wait for the container to build β€” it installs dependencies with `pip install -r requirements.txt` +2. Wait for the container to build β€” it installs dependencies with `pip install -r src/requirements.txt` automatically. When the terminal stops scrolling and shows a prompt, it's ready. βœ… **You'll know it worked when:** a **VS Code** window opens (locally or in the browser) with a **Terminal** panel showing a -ready prompt (e.g. `@your-username ➜ /workspaces/microhack-aiagents (main) $`). +ready prompt. > [!NOTE] -> **Prefer the browser? Use GitHub Codespaces instead.** On the repo's GitHub page, click **`< > Code` β†’ Codespaces β†’ Create codespace on `main`** β€” the same dev container builds in the cloud, so you need no local Docker. If Codespaces isn't enabled in your org, see [enabling Codespaces](https://docs.github.com/en/codespaces/managing-codespaces-for-your-organization/enabling-or-disabling-github-codespaces-for-your-organization) or use a [free personal account](https://github.com/signup) (120 core-hours/month free). +> **Prefer the browser? Use GitHub Codespaces instead.** On the repo's GitHub page, click **`< > Code` β†’ Codespaces β†’ Create codespace on `main`** β€” the same dev container builds in the cloud, so you need no local Docker. > > While it builds, skim the [scenario & architecture](../README.md#the-scenario--contoso-global) so the pieces you deploy here make sense. @@ -245,6 +244,7 @@ everything. First pick a region that offers **all three** models β€” this repo's > old template is what triggers `DeploymentModelNotSupported` / `ServiceModelDeprecating`. ```bash +cd src # azure.yaml (the azd project) lives here azd auth login # separate from az login above azd up # answer: environment name (e.g. clm-microhack), your subscription, region = Sweden Central ``` diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-04.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-04.md index 9dd76b121..ad3ec02ee 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-04.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/challenges/challenge-04.md @@ -272,7 +272,7 @@ agent, your orchestrator) can reach. No editor required. #### Part A Β· Host the server on Azure Container Apps -The server already speaks HTTP β€” `--http` (what the repo-root [`Dockerfile`](../Dockerfile) runs) serves +The server already speaks HTTP β€” `--http` (what the src/ [`Dockerfile`](../src/Dockerfile) runs) serves **streamable HTTP** at `/mcp` on port 8000. Deploy it (image builds **in the cloud** β€” no local Docker) from the **repo root**. The script **reads your `.env`** (the same one the agents use) and **auto-discovers** the resource group, Foundry account and region from your project endpoint β€” so there's @@ -362,12 +362,12 @@ at your URL. | `clm-mcp` not in *MCP: List Servers* | VS Code discovers a workspace MCP server only from `.vscode/mcp.json` at the **root of the opened folder** β€” running `python src/mcp_server/server.py` in a terminal does **not** register it. Open the **repo root** (not `src/`) and confirm the file is at `/.vscode/mcp.json`. If it's missing there, **pull the latest hack repo** (older copies shipped it under `src/.vscode/`), then reload VS Code. | | `Invalid JSON … Internal Server Error` after starting the server | **Harmless.** You typed or pressed **Enter** in the stdio window, so the server rejected the newline as invalid JSON-RPC. It's still running β€” don't type into it. Use `python src/mcp_server/server.py --list` to confirm the tools without the stdio loop. | | Orchestrator doesn't route correctly | Sharpen the routing rules in `INSTRUCTIONS`; make each specialist's `as_tool(description=...)` specific. | -| `ImportError: cannot import name 'Agent' from 'agent_framework'` (or other `agent_framework` import errors) | You have an **old/mismatched build**, or you `pip install`ed into a **different Python** than the one running the script (common with Microsoft Store Python). First see **which** interpreter actually runs the script: `python -c "import sys; print(sys.executable)"`. Then reinstall the pinned deps into **that same** interpreter β€” the `-U` matters, a plain install won't replace a stale version: `python -m pip install -U -r requirements.txt`. Finally verify: `python -c "import agent_framework as a; print(a.__version__)"` β€” you need **β‰₯ 1.11.0**. | +| `ImportError: cannot import name 'Agent' from 'agent_framework'` (or other `agent_framework` import errors) | You have an **old/mismatched build**, or you `pip install`ed into a **different Python** than the one running the script (common with Microsoft Store Python). First see **which** interpreter actually runs the script: `python -c "import sys; print(sys.executable)"`. Then reinstall the pinned deps into **that same** interpreter β€” the `-U` matters, a plain install won't replace a stale version: `python -m pip install -U -r src/requirements.txt`. Finally verify: `python -c "import agent_framework as a; print(a.__version__)"` β€” you need **β‰₯ 1.11.0**. | | MCP server not listed in VS Code | Ensure the MCP feature is enabled and `mcp.json` path is correct; confirm the server imports cleanly first with `python src/mcp_server/server.py --list`. | | MCP tool call times out | Each call spins up + tears down a Foundry agent (a few seconds). Keep drafts short while testing. | | `orchestrator_mcp.py` finds no tools / hangs at startup | The stdio server failed to import. Confirm `python src/mcp_server/server.py` starts standalone; `MCPStdioTool` sets `PYTHONPATH=src`, so run from the repo root. | | Web search tool not attaching | Confirm `AZURE_BING_CONNECTION_NAME` matches a **project connection** for your Grounding with Bing Search resource; run `python src/kb_setup.py` β€” it prints whether the web-grounding tool built. | -| `deploy.sh` fails / `az containerapp up` errors | Ensure `az` β‰₯ 2.53 and the **containerapp** extension (`az extension add -n containerapp`), you're logged in (`az login`) and on the lab subscription (`az account set -s `), and you're running it from the **repo root** (build context needs `Dockerfile`, `requirements.txt`, `src/`). First run also registers the `Microsoft.App`/`Microsoft.OperationalInsights` providers β€” that can take a minute. | +| `deploy.sh` fails / `az containerapp up` errors | Ensure `az` β‰₯ 2.53 and the **containerapp** extension (`az extension add -n containerapp`), you're logged in (`az login`) and on the lab subscription (`az account set -s `), and you're running it from the **repo root** (the script builds from the `src/` context β€” `src/Dockerfile`, `src/requirements.txt`, app code). First run also registers the `Microsoft.App`/`Microsoft.OperationalInsights` providers β€” that can take a minute. | | Foundry agent shows the MCP tool but tool calls fail / time out | Check the app is reachable: open `https://.azurecontainerapps.io/mcp` β€” it should respond (405/JSON, not a connection error). Confirm ingress is **external** (`az containerapp ingress show`), the URL **ends with `/mcp`**, and the Server URL in Foundry matches exactly. | | Remote tools return `401/403` / "credential" errors from Foundry | The **container's managed identity** lacks a data-plane role on your Foundry account. Re-run the role step in `deploy.sh` (or assign **Azure AI User** on `FOUNDRY_ACCOUNT_ID`), then wait ~1 min for propagation. Verify with `az containerapp identity show` + `az role assignment list --assignee `. | | `CLM_MCP_URL` run: connection refused / hangs | Confirm the app is running (`az containerapp show --query properties.runningStatus`) and the URL includes `/mcp`. If you added a key, set `CLM_MCP_KEY` too. Unset `CLM_MCP_URL` to fall back to the local stdio server. | diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/README.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/README.md index bf7777bcf..08c8f4ad2 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/README.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/README.md @@ -7,7 +7,7 @@ network β€” no local process required. ## What gets deployed - A single **Azure Container App** named `clm-mcp` (external HTTPS ingress on - port `8000`) built from the repo‑root [`Dockerfile`](../../Dockerfile). + port `8000`) built from the src/ [`Dockerfile`](../../src/Dockerfile). - The app runs `python src/mcp_server/server.py --http`, exposing the MCP endpoint at `https://..azurecontainerapps.io/mcp`. - A **system‑assigned managed identity** granted a data‑plane role on your diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.ps1 b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.ps1 index a87e2853b..7e6374334 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.ps1 +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.ps1 @@ -5,7 +5,7 @@ ----------------------------------------------------------------------------- Windows/PowerShell twin of deploy.sh. Builds the image in the cloud (no local Docker) and prints the /mcp URL a Foundry agent connects to. Run it from the - REPO ROOT so the build context (requirements.txt + src/) is correct. + REPO ROOT; the build context is the src/ folder (Dockerfile + requirements.txt + app code). ZERO-CONFIG by default: reads your repo-root .env for AZURE_AI_PROJECT_ENDPOINT + MODEL_*, then auto-discovers the resource group, Foundry account id and region @@ -94,7 +94,7 @@ az containerapp up ` --name $AppName ` --resource-group $ResourceGroup ` --location $Location ` - --source . ` + --source src ` --ingress external ` --target-port 8000 ` --env-vars ` diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.sh b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.sh index 3d3562aba..cd99c8f64 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.sh +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/deploy/mcp-server/deploy.sh @@ -3,8 +3,8 @@ # Challenge 4 Β· Deploy the CLM MCP server to Azure Container Apps (remote MCP) # ----------------------------------------------------------------------------- # Builds the image in the cloud (no local Docker needed) and prints the /mcp URL -# a Foundry agent connects to. Run this from the REPO ROOT so the Docker build -# context (requirements.txt + src/) is correct. +# a Foundry agent connects to. Run this from the REPO ROOT; the Docker build +# context is the src/ folder (Dockerfile + requirements.txt + app code). # # ZERO-CONFIG by default: it reads your repo-root `.env` (the same file the # agents use) for AZURE_AI_PROJECT_ENDPOINT + MODEL_*, then auto-discovers the @@ -85,7 +85,7 @@ az containerapp up \ --name "$APP_NAME" \ --resource-group "$RESOURCE_GROUP" \ --location "$LOCATION" \ - --source . \ + --source src \ --ingress external \ --target-port 8000 \ --env-vars \ diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/docs/coach-guide.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/docs/coach-guide.md index efe5bfe1b..cb7a21364 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/docs/coach-guide.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/docs/coach-guide.md @@ -150,7 +150,7 @@ of the challenge, what "done" looks like, where teams get stuck, and the hint to - **Watch for:** - *Orchestrator routes wrong* β†’ sharpen `INSTRUCTIONS` routing rules and make each specialist's `as_tool(description=...)` specific. - - *`agent_framework` import error* β†’ `pip install agent-framework-core agent-framework-foundry` (see requirements.txt). + - *`agent_framework` import error* β†’ `pip install agent-framework-core agent-framework-foundry` (see src/requirements.txt). - *MCP server not listed in VS Code* β†’ the workspace config must be at the repo-root `.vscode/mcp.json` and you must open the **repo root** (not `src/`); confirm the server imports cleanly first (`python src/mcp_server/server.py --list`). - *(Task 4) Remote deploy* β†’ run `bash deploy/mcp-server/deploy.sh` from the **repo root** (needs the diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/README.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/README.md index 99eec7f91..11c961e5e 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/README.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/labautomation/README.md @@ -41,7 +41,7 @@ same resources from `infra/`. [`infra/`](infra/) holds the Bicep templates (plus `azuredeploy.json` for the one-click **Deploy to Azure** button) that create the Microsoft Foundry project, the three GPT model deployments (`gpt-5.4`, `gpt-5.6-sol`, `gpt-5.4-nano`), Azure AI Search, Azure SQL, and Application Insights. -`azure.yaml` at the repo root points `azd` at this folder. +`src/azure.yaml` points `azd` at this folder (`../labautomation/infra`); run `azd up` from `src/`. ## Scripts @@ -68,7 +68,7 @@ Seeding, setup & gate scripts β€” run by participants/coaches during the hack ```bash az login -./labautomation/deploy.sh # or: azd up (Windows: labautomation\deploy.ps1) +./labautomation/deploy.sh # or: (cd src && azd up) (Windows: labautomation\deploy.ps1) # Default corpus path (own admin tenant): SharePoint app + consent + site + upload + index python src/scripts/setup_sharepoint_corpus.py # β€” or the no-SharePoint fallback: python src/scripts/seed_corpus.py diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.dockerignore b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.dockerignore new file mode 100644 index 000000000..faf0b6e39 --- /dev/null +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.dockerignore @@ -0,0 +1,18 @@ +# The build context IS this src/ folder β€” it holds the Dockerfile, requirements.txt +# and all the app code the CLM MCP server needs (Dockerfile does COPY . ./src/). +# Exclude only caches, local secrets, and build/config files not needed at runtime. +**/__pycache__ +**/*.pyc +**/*.pyo +**/.pytest_cache + +# Never bake local secrets into the image +.env +.env.* +!.env.example + +# Build/config files the running server image doesn't need +.gitignore +.gitattributes +.dockerignore +azure.yaml diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitattributes b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.gitattributes similarity index 100% rename from 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitattributes rename to 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.gitattributes diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.gitignore similarity index 95% rename from 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore rename to 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.gitignore index 2e7550844..8d31e92ee 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/.gitignore @@ -20,7 +20,7 @@ node_modules/ *.log *.pdf # ...but the Challenge 1 CLM corpus PDFs ARE seed data and must be tracked. -!src/data/**/*.pdf +!data/**/*.pdf dist/ build/ diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/Dockerfile b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/Dockerfile similarity index 78% rename from 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/Dockerfile rename to 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/Dockerfile index a093187ce..c336799f2 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/Dockerfile +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/Dockerfile @@ -2,10 +2,11 @@ # ============================================================================= # Challenge 4 β€” container image for the CLM MCP server (remote / streamable-HTTP) # ----------------------------------------------------------------------------- -# The build CONTEXT must be the REPO ROOT β€” the image needs requirements.txt and -# src/. Deploy it with one command (builds in the cloud, no local Docker needed): +# The build CONTEXT is this `src/` folder β€” it holds this Dockerfile, +# requirements.txt and all the app code (COPY . ./src/). Deploy it with one +# command (builds in the cloud, no local Docker needed) by pointing at src/: # -# az containerapp up -n clm-mcp -g --source . \ +# az containerapp up -n clm-mcp -g --source ./src \ # --target-port 8000 --ingress external \ # --env-vars AZURE_AI_PROJECT_ENDPOINT= # @@ -34,7 +35,9 @@ RUN apt-get update \ COPY requirements.txt ./ RUN pip install -r requirements.txt -COPY src/ ./src/ +# The build context IS this src/ folder, so copy it all into /app/src/ (caches and +# build/config files are pruned by .dockerignore). CMD below runs src/mcp_server/server.py. +COPY . ./src/ EXPOSE 8000 diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/README.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/README.md index d36686b22..fa6edc843 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/README.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/README.md @@ -21,7 +21,7 @@ helpers live in [`clm_common/`](clm_common/); every entry-point script adds `src | [`mcp_server/server.py`](mcp_server/server.py) | MCP server exposing the CLM workflow β€” stdio (local) **and** streamable HTTP (`--http`, for hosting) | 4 | | [`../.vscode/mcp.json`](../.vscode/mcp.json) | VS Code MCP client config (`clm-mcp`, repo root) | 4 | | [`orchestrator_mcp.py`](orchestrator_mcp.py) | Orchestrator as MCP client β€” local stdio, or remote via `CLM_MCP_URL` | 4 | -| [`../Dockerfile`](../Dockerfile) + [`../deploy/mcp-server/`](../deploy/mcp-server/) | Containerize + deploy the MCP server to Azure Container Apps (remote `/mcp` for Foundry) | 4 | +| [`Dockerfile`](Dockerfile) + [`../deploy/mcp-server/`](../deploy/mcp-server/) | Containerize + deploy the MCP server to Azure Container Apps (remote `/mcp` for Foundry) | 4 | | [`manifest/`](manifest/) | Teams / M365 Copilot app package (manifest + icons) | 5 | | [`red_team.py`](red_team.py) | Automated red-teaming β†’ `redteam_scorecard.json` | 6 | | [`safety_eval.py`](safety_eval.py) | Safety evaluation + CLM guardrail gate | 6 | @@ -40,5 +40,5 @@ python src/orchestrator.py # Challenge 4 β€” orchestration ``` > Config is read from the repo-root `.env` via `clm_common/config.py`. Run -> [`../labautomation/deploy.sh`](../labautomation/deploy.sh) (or `azd up`) first so the +> [`../labautomation/deploy.sh`](../labautomation/deploy.sh) (or `cd src && azd up`) first so the > `.env` is populated and the corpus is seeded. diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/azure.yaml b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/azure.yaml similarity index 68% rename from 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/azure.yaml rename to 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/azure.yaml index 63091a8ff..5b50484b1 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/azure.yaml +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/azure.yaml @@ -1,7 +1,8 @@ # ========================================================================== # Foundry CLM Microhack β€” Azure Developer CLI (azd) configuration -# `azd up` provisions the full Foundry environment defined in labautomation/infra/ and then -# writes a repo-root .env matching labautomation/deploy.sh. +# This file lives in src/, so run azd from there: `cd src && azd up`. +# `azd up` provisions the full Foundry environment defined in ../labautomation/infra/ +# and then writes a repo-root .env matching labautomation/deploy.sh. # Docs: https://aka.ms/azure-dev/schema # ========================================================================== name: foundry-clm-microhack @@ -10,7 +11,7 @@ metadata: infra: provider: bicep - path: labautomation/infra + path: ../labautomation/infra module: main hooks: @@ -19,11 +20,11 @@ hooks: postprovision: windows: shell: pwsh - run: python src/scripts/write_env.py + run: python scripts/write_env.py continueOnError: false interactive: false posix: shell: sh - run: python3 src/scripts/write_env.py + run: python3 scripts/write_env.py continueOnError: false interactive: false diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/clm_common/documents.py b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/clm_common/documents.py index 4307f9a1a..3ee64a827 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/clm_common/documents.py +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/clm_common/documents.py @@ -26,7 +26,7 @@ def read_document_text(path: str | Path) -> str: except ImportError as exc: # pragma: no cover - dependency hint raise RuntimeError( "Reading PDF documents requires 'pypdf'. Install it with " - "`pip install pypdf` (it is listed in requirements.txt)." + "`pip install pypdf` (it is listed in src/requirements.txt)." ) from exc reader = PdfReader(str(path)) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/red_team.py b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/red_team.py index 97983656d..547042f04 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/red_team.py +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/red_team.py @@ -15,7 +15,7 @@ python src/red_team.py --num-objectives 3 --output redteam_scorecard.json Requires: `pip install "azure-ai-evaluation[redteam]"` (pulls PyRIT) and an -Azure AI (Foundry) project + login. See requirements.txt. +Azure AI (Foundry) project + login. See src/requirements.txt. """ from __future__ import annotations diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/requirements.txt b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/requirements.txt similarity index 100% rename from 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/requirements.txt rename to 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/requirements.txt diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/make_step_placeholders.py b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/make_step_placeholders.py index a2f62e177..b2dc3d2d8 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/make_step_placeholders.py +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/make_step_placeholders.py @@ -25,7 +25,7 @@ ("challenge-0", "02-create-codespace", "GitHub Β· Create Codespace", "Code button β†’ Codespaces tab β†’ 'Create codespace on main' green button."), ("challenge-0", "03-codespace-ready", "Codespace Β· Ready", - "The VS Code-in-browser Codespace with a terminal open and 'pip install -r requirements.txt' finished."), + "The VS Code-in-browser Codespace with a terminal open and 'pip install -r src/requirements.txt' finished."), ("challenge-0", "04-az-login-device", "Azure Β· Device-code login", "The https://microsoft.com/devicelogin page where you paste the code printed by 'az login --use-device-code'."), ("challenge-0", "05-azd-up-prompts", "azd up Β· Prompts", diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/setup_sharepoint_corpus.py b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/setup_sharepoint_corpus.py index d443f7114..29bd843b3 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/setup_sharepoint_corpus.py +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/setup_sharepoint_corpus.py @@ -337,14 +337,15 @@ def upsert_env(values: dict[str, str]) -> None: print(f" βœ“ wrote SHAREPOINT_* values to {ENV_PATH}") # Best-effort: mirror into the azd environment so a later `azd provision`/`azd up` - # regenerates .env with these values instead of blanking them. + # regenerates .env with these values instead of blanking them. azure.yaml lives + # in src/, so run azd from there. azd = shutil.which("azd") if azd: for key in SHAREPOINT_KEYS: if key in values: subprocess.run( [azd, "env", "set", key, values[key]], - cwd=REPO_ROOT, capture_output=True, text=True, check=False, + cwd=REPO_ROOT / "src", capture_output=True, text=True, check=False, ) diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/write_env.py b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/write_env.py index 23179dd18..b0c9ed763 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/write_env.py +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/src/scripts/write_env.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Write the repo-root .env from deployment outputs. -By default this runs as the azd `postprovision` hook (see azure.yaml) and reads +By default this runs as the azd `postprovision` hook (see src/azure.yaml) and reads the provisioned values via `azd env get-values`. Pass `--deployment ` to instead read the outputs of a subscription-scoped ARM deployment (the plain-ARM / "Deploy to Azure" path using infra/azuredeploy.json), e.g.: @@ -21,6 +21,8 @@ REPO_ROOT = Path(__file__).resolve().parents[2] ENV_PATH = REPO_ROOT / ".env" +# azure.yaml (the azd project) lives in src/, so azd commands must run from there. +AZD_DIR = REPO_ROOT / "src" # Keys sourced from Bicep outputs (via azd env). Fall back to the src/.env.example # defaults for the constant-valued ones if an output is missing. @@ -40,12 +42,12 @@ } -def _run(cmd: list[str]) -> str: - """Run a command in the repo root, exiting with a friendly message on error.""" +def _run(cmd: list[str], cwd: Path = REPO_ROOT) -> str: + """Run a command (default cwd = repo root), exiting with a friendly message on error.""" try: proc = subprocess.run( cmd, - cwd=REPO_ROOT, + cwd=cwd, capture_output=True, text=True, check=True, @@ -59,7 +61,7 @@ def _run(cmd: list[str]) -> str: def azd_env_values() -> dict[str, str]: """Return azd environment values as a dict (parsing KEY="value" lines).""" - stdout = _run(["azd", "env", "get-values"]) + stdout = _run(["azd", "env", "get-values"], cwd=AZD_DIR) values: dict[str, str] = {} for line in stdout.splitlines(): line = line.strip() diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-01/solution-01.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-01/solution-01.md index 302fa5d45..f38d5040c 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-01/solution-01.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-01/solution-01.md @@ -27,7 +27,7 @@ contract corpus the later challenges ground on. ## πŸ› οΈ Task-by-task walkthrough ### Task 1 Β· Open the Codespace -No fork β€” the code lives in this repo. **`< > Code` β–Έ Codespaces β–Έ Create codespace on `main`**; the devcontainer builds and `pip install -r requirements.txt` runs automatically. *(Local alt: `git clone` then **Reopen in Container**.)* +No fork β€” the code lives in this repo. **`< > Code` β–Έ Codespaces β–Έ Create codespace on `main`**; the devcontainer builds and `pip install -r src/requirements.txt` runs automatically. *(Local alt: `git clone` then **Reopen in Container**.)* > πŸ“Έ **Screenshot slot:** creating the **Codespace**. > @@ -63,9 +63,10 @@ The model names + `AZURE_SEARCH_INDEX` (`clm-corpus`) / `AZURE_SEARCH_CONNECTION Self-hosting? One azd up provisions everything and writes .env for you ```bash +cd src # azure.yaml (the azd project) lives here azd auth login # separate from az login above azd up # env name, subscription, region = Sweden Central (offers all three models) -# β€” or the scripted path β€” LOCATION=swedencentral ./labautomation/deploy.sh (deploy.ps1 on Windows) +# β€” or the scripted path β€” LOCATION=swedencentral ./labautomation/deploy.sh (deploy.ps1 on Windows; from repo root) ``` The `postprovision` hook β†’ [`src/scripts/write_env.py`](../../src/scripts/write_env.py) reads the deployment outputs (`azd env get-values`, or `--deployment` for the ARM path) and writes every env var the agents use β€” filling constants from a `DEFAULTS` map when an output is absent, so you can skip the manual paste above: ```python diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-04/solution-04.md b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-04/solution-04.md index f067def15..0ce50b6a5 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-04/solution-04.md +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/walkthrough/challenge-04/solution-04.md @@ -17,7 +17,7 @@ called from a **Foundry** agent by URL. `draft_contract` Β· `analyze_contract` Β· `get_contract_status` over **stdio** (local) and **streamable HTTP** (`--http`, for hosting); VS Code loads the stdio server from [`.vscode/mcp.json`](../../.vscode/mcp.json) (repo root). -- [`Dockerfile`](../../Dockerfile) + [`deploy/mcp-server/deploy.sh`](../../deploy/mcp-server/deploy.sh) +- [`Dockerfile`](../../src/Dockerfile) + [`deploy/mcp-server/deploy.sh`](../../deploy/mcp-server/deploy.sh) host it on **Azure Container Apps** as a remote `https://…/mcp` endpoint a Foundry agent can call. - [`src/orchestrator_mcp.py`](../../src/orchestrator_mcp.py) runs the same GPT-5.4 orchestrator as an **MCP client** β€” local stdio, or the remote server via `CLM_MCP_URL`. @@ -118,9 +118,9 @@ spawns the stdio server for you (no IDE) and runs draft β†’ analyze β†’ status o start **clm-mcp** β†’ call `#analyze_contract` in Copilot Chat. ### Task 4 Β· Host it remotely + call it from Foundry -**Part A β€” host on Azure Container Apps.** The repo-root [`Dockerfile`](../../Dockerfile) runs +**Part A β€” host on Azure Container Apps.** The src/ [`Dockerfile`](../../src/Dockerfile) runs `server.py --http` (streamable HTTP at `/mcp`). Deploy from the repo root β€” the image builds in the -cloud, no local Docker: +cloud (from the `src/` context), no local Docker: ```bash bash deploy/mcp-server/deploy.sh # reads .env, auto-discovers RG/account/region β†’ https://clm-mcp..azurecontainerapps.io/mcp ``` @@ -174,7 +174,7 @@ propagation takes ~1 min, so just re-run the script or wait if a later model cal | [`src/mcp_server/server.py`](../../src/mcp_server/server.py) | MCP server exposing the CLM workflow (stdio **and** streamable HTTP via `--http`) | | [`.vscode/mcp.json`](../../.vscode/mcp.json) | VS Code MCP client config (`clm-mcp`, repo root) | | [`src/orchestrator_mcp.py`](../../src/orchestrator_mcp.py) | Orchestrator as MCP client β€” local stdio, or remote via `CLM_MCP_URL` | -| [`Dockerfile`](../../Dockerfile) + [`deploy/mcp-server/deploy.sh`](../../deploy/mcp-server/deploy.sh) | Containerize + deploy the server to Azure Container Apps as a remote `/mcp` endpoint | +| [`Dockerfile`](../../src/Dockerfile) + [`deploy/mcp-server/deploy.sh`](../../deploy/mcp-server/deploy.sh) | Containerize + deploy the server to Azure Container Apps as a remote `/mcp` endpoint | ## Run it From 645df3e81920232970c95c942d7929c16e7187d7 Mon Sep 17 00:00:00 2001 From: glejdisshkembi <53597226+glejdis@users.noreply.github.com> Date: Wed, 19 Aug 2026 16:59:03 +0200 Subject: [PATCH 7/7] Sync CLM hack from glejdis main: dev container Azure SQL driver + root .gitignore Mirrors glejdis/microhack-aiagents#111 into the upstream hack path: add .gitignore (protects repo-root .env), .devcontainer/post-create.sh (pip install + best-effort msodbcsql18), .devcontainer/.gitattributes, and point devcontainer.json postCreateCommand at the script. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 84082b7c-f262-4c92-90b7-1649bce45bfc --- .../.devcontainer/.gitattributes | 3 ++ .../.devcontainer/devcontainer.json | 2 +- .../.devcontainer/post-create.sh | 40 +++++++++++++++++++ .../.gitignore | 24 +++++++++++ 4 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/.gitattributes create mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/post-create.sh create mode 100644 03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/.gitattributes b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/.gitattributes new file mode 100644 index 000000000..43b1d6258 --- /dev/null +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/.gitattributes @@ -0,0 +1,3 @@ +# Keep the post-create hook LF so bash inside the dev container doesn't choke on +# CRLF when the repo is checked out on Windows. +*.sh text eol=lf diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json index 9ed6ddf9d..f9d80e1ee 100644 --- a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/devcontainer.json @@ -9,7 +9,7 @@ }, "ghcr.io/devcontainers/features/github-cli:1": {} }, - "postCreateCommand": "pip install --upgrade pip && pip install -r src/requirements.txt", + "postCreateCommand": "bash .devcontainer/post-create.sh", "customizations": { "vscode": { "extensions": [ diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/post-create.sh b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/post-create.sh new file mode 100644 index 000000000..9e29a8141 --- /dev/null +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.devcontainer/post-create.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# ============================================================================= +# Dev container post-create hook (runs once after the container is built). +# +# 1. Install the Python dependencies (src/requirements.txt) β€” ESSENTIAL: +# every challenge needs these. +# 2. Best-effort install of the Microsoft ODBC Driver 18 for SQL Server so the +# OPTIONAL Azure SQL contract-status / renewal tool works out of the box. +# That tool's connection string uses "Driver={ODBC Driver 18 for SQL +# Server}" (see labautomation/infra/resources.bicep), so unixODBC alone is +# not enough. If this step fails (e.g. no network to packages.microsoft.com) +# the tool simply falls back to the bundled JSON corpus, so we NEVER fail +# the whole container build over an optional driver. +# ============================================================================= +set -euo pipefail + +echo "==> [1/2] Installing Python dependencies (src/requirements.txt)" +pip install --upgrade pip +pip install -r src/requirements.txt + +echo "==> [2/2] Installing Microsoft ODBC Driver 18 for SQL Server (optional Azure SQL tool)" +if command -v odbcinst >/dev/null 2>&1 && odbcinst -q -d 2>/dev/null | grep -q "ODBC Driver 18 for SQL Server"; then + echo " Driver already present β€” skipping." +else + # Debian 12 (bookworm) β€” matches the python:3.11-bookworm base image. + if ( + set -e + curl -sSL -O https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + rm -f packages-microsoft-prod.deb + sudo apt-get update + sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 + ); then + echo " ODBC Driver 18 installed." + else + echo " WARN: msodbcsql18 install failed β€” the Azure SQL tool will use the JSON fallback." + fi +fi + +echo "==> post-create complete." diff --git a/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore new file mode 100644 index 000000000..47533eee1 --- /dev/null +++ b/03-Azure/01-04-AI/04_Agentic_Contract_Lifecycle_Management/.gitignore @@ -0,0 +1,24 @@ +# Secrets / local config +# The repo-root .env is written by src/scripts/write_env.py and holds live +# secrets (SharePoint app secret, connection strings). Never commit it. +.env +.env.* +!.env.example + +# Python (local runs at the repo root) +__pycache__/ +*.py[cod] +.venv/ +venv/ +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.python-version + +# OS +.DS_Store +Thumbs.db + +# Azure / tooling +.azure/ +*.azd