Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "Foundry CLM Microhack",
"image": "mcr.microsoft.com/devcontainers/python:3.11-bookworm",
"features": {
"ghcr.io/devcontainers/features/azure-cli:1": {},
"ghcr.io/azure/azure-dev/azd:0": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"postCreateCommand": "pip install --upgrade pip && pip install -r requirements.txt",
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.vscode-pylance",
"ms-azuretools.vscode-azureresourcegroups",
"ms-azuretools.vscode-bicep",
"teamsdevapp.ms-teams-vscode-extension",
"github.copilot",
"github.copilot-chat"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python"
}
}
},
"remoteEnv": {
"PYTHONPATH": "${containerWorkspaceFolder}/src"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# ==========================================================================
# Foundry CLM Microhack — environment template
# Copy to `.env` (never commit `.env`). Challenge 1's deploy script autofills
# most of these for you. Fill the Bot values in Challenge 5.
# ==========================================================================

# --- Foundry project ------------------------------------------------------
# Project endpoint, copied from the Foundry portal (Overview → Endpoint).
# Example: https://<account>.services.ai.azure.com/api/projects/<project>
AZURE_AI_PROJECT_ENDPOINT=

# --- Model deployments (multi-model fleet) --------------------------------
# Deployment names you created in Challenge 1. Intake & Drafting runs on Claude
# (GA in Microsoft Foundry); Clause & Risk runs on GPT-5.6 Sol; the orchestrator
# + lightweight agent run on GPT. If you skipped Claude (DEPLOY_CLAUDE_MODEL=false
# — no quota/marketplace offer), set MODEL_DRAFTING to gpt-5.4 instead.
MODEL_ORCHESTRATOR=gpt-5.4
MODEL_DRAFTING=claude-opus-4-8
MODEL_CLAUSE_RISK=gpt-5.6-sol
MODEL_RENEWAL=gpt-5-mini

# --- Azure AI Search (Foundry IQ knowledge base) --------------------------
AZURE_SEARCH_ENDPOINT=
AZURE_SEARCH_INDEX=clm-corpus
AZURE_SEARCH_CONNECTION_NAME=clm-search

# --- Web grounding (Grounding with Bing Search) — OPTIONAL --------------
# Opt-in. Attaches a web-search tool to the Clause & Risk agent (Ch4) for
# external, PUBLIC counterparty due-diligence (corporate status, adverse-media,
# sanctions, regulatory references). Provision a "Grounding with Bing Search"
# resource, add it as a project connection, then set its NAME below (or set the
# connection id directly). Leave blank to keep web search off (zero setup).
# NOTE: Bing search data leaves the Azure compliance boundary. Later swap to
# Web IQ by editing build_web_search_tool() only — no env change needed.
AZURE_BING_CONNECTION_NAME=
# AZURE_BING_CONNECTION_ID= # optional: skip name resolution with an explicit id

# --- SharePoint (corpus source of truth — BYO document library) -----------
# The original contract PDFs live in a SharePoint document library. An Azure AI
# Search SharePoint Online indexer (created by src/scripts/seed_corpus.py) crawls
# the library into the clm-corpus index that Foundry IQ grounds on.
# OPTIONAL: leave these blank to use the LOCAL-PDF fallback — seed_corpus.py then
# extracts text from src/data/**/*.pdf and pushes it straight into the
# clm-corpus index (no SharePoint needed; ideal for sandbox tenants without an
# SPO license or admin-consent rights).
# SHAREPOINT_SITE_URL example: https://contoso.sharepoint.com/sites/CLMCorpus
SHAREPOINT_SITE_URL=
SHAREPOINT_DOC_LIBRARY=Documents
# App registration (Microsoft Entra) authorizing the indexer — Graph app-only
# auth (Sites.Read.All / Files.Read.All, admin-consented). See challenge-0 README.
# To also *upload* the corpus PDFs with src/scripts/upload_corpus_to_sharepoint.py,
# the app needs Sites.ReadWrite.All (or Files.ReadWrite.All), admin-consented.
SHAREPOINT_APP_ID=
SHAREPOINT_APP_SECRET=
SHAREPOINT_TENANT_ID=

# --- Observability (Challenge 3) ------------------------------------------
APPLICATIONINSIGHTS_CONNECTION_STRING=
# Capture prompt/response content in traces (dev only — PII implications).
AZURE_TRACING_GEN_AI_CONTENT_RECORDING_ENABLED=true

# --- Eval judge / LLM-as-a-judge (Challenge 3) ----------------------------
# OPTIONAL. src/evaluators.py runs Azure AI "quality" evaluators
# (Relevance/Coherence/Groundedness) that need a judge model. Leave these
# blank to reuse the Foundry PROJECT_ENDPOINT + MODEL_ORCHESTRATOR deployment
# with your AAD login (default). Set them to point the judge at a dedicated
# Azure OpenAI deployment (e.g. a cheaper/faster model) or to use an API key.
# AZURE_OPENAI_ENDPOINT=https://<your-aoai>.openai.azure.com/
# AZURE_OPENAI_DEPLOYMENT=gpt-5-mini
# AZURE_OPENAI_API_VERSION=2024-10-21
# AZURE_OPENAI_API_KEY=
# Evaluator batch concurrency. Lower it (or pass --workers) if a shared judge
# deployment returns 429 rate-limits. Defaults to 2 when unset.
# PF_WORKER_COUNT=2

# --- Azure SQL (contract status / renewal dates function tool) ------------
AZURE_SQL_CONNECTION_STRING=

# --- Publish + proactive Teams alerts (Challenge 5) -----------------------
MICROSOFT_APP_ID=
MICROSOFT_APP_PASSWORD=
MICROSOFT_APP_TENANT_ID=
# Captured from an inbound Teams activity; used to push proactive alerts.
TEAMS_SERVICE_URL=
TEAMS_CONVERSATION_ID=
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Treat PDFs as binary so Git never applies end-of-line conversion to them
# (the CLM contract corpus PDFs would otherwise be corrupted on checkout).
*.pdf binary
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.pptx binary
*.docx binary
*.xlsx binary
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
description: "Use when you want to validate that this hack is fully compliant with the microsoft/MicroHack platform conventions. Checks directory naming, deploy-lab.ps1 parameter contract, lab-defaults.json schema validity, platform integration rules (no Connect-AzAccount, no premature RG creation), credential return pattern, and content structure. Run before committing or requesting platform access."
name: "Hack Compliance Validator"
tools: [read, search]
user-invocable: true
argument-hint: "Validate this hack for EMEA platform compliance"
---

You are a strict EMEA MicroHack platform compliance auditor based on [microsoft/MicroHack](https://github.com/microsoft/MicroHack).
Inspect this workspace and produce a pass/fail report against every mandatory convention.

## Compliance Checklist

Work through each item. Mark ✅ PASS or ❌ FAIL with a brief reason.

### 1. Directory Structure
- [ ] `labautomation/` directory exists (no dashes — exactly `labautomation`).
- [ ] `labautomation/` contains **only** `deploy-lab.ps1`, `lab-defaults.json`, and `README.md` — no stray files (facilitator notes, runbooks, secrets, etc.). One-time setup / prerequisite docs belong in `walkthrough/` or a separate top-level folder, not here.
- [ ] `labautomation/lab-defaults.json` exists.
- [ ] `labautomation/README.md` exists.
- [ ] The root readme is **`README.md`** (all caps), and **every link that targets it uses that exact casing** — the `[Home]` links in `challenges/` (`../README.md`) and `walkthrough/` (`../../README.md`). GitHub is case-sensitive, so a `../Readme.md` link would 404. Flag any casing mismatch as **blocking** — even though it resolves on Windows.
- [ ] `challenges/` directory exists.
- [ ] `walkthrough/` directory exists.

### 2. deploy-lab.ps1 — Parameter Contract
- [ ] `labautomation/deploy-lab.ps1` exists (optional but recommended).
- [ ] If it exists: parameter block declares exactly `$DeploymentType`, `$SubscriptionId`, `$ResourceGroupName`, `$PreferredLocation`, `$AllowedEntraUserIds`.
- [ ] `$DeploymentType` has `[ValidateSet('subscription','resourcegroup','resourcegroup-with-subscriptionowner')]`.

### 3. deploy-lab.ps1 — Platform Integration Rules
- [ ] Script does **NOT** call `Connect-AzAccount` (platform pre-sets Az context).
- [ ] For `resourcegroup` deployment type: script does **NOT** call `New-AzResourceGroup` (platform pre-creates it).
- [ ] For `subscription` deployment type: script uses `Get-MhhStableHash` to generate a deterministic RG name.
- [ ] Any `Get-MhhStableHash` call passes `-Length` within the valid **12–64** range. Values below 12 throw at runtime and silently fail the whole deployment — flag as **blocking**.

### 4. deploy-lab.ps1 — Credential Return
- [ ] Script emits at least one `@{ HackboxCredential = @{ name = ...; value = ...; note = ... } }` to the output stream.

### 5. lab-defaults.json — Schema Validity
- [ ] File is valid JSON (no comments, no trailing commas).
- [ ] Contains `"$schema"` pointing to the MicroHack schema URL.
- [ ] `deploymentType` is one of: `"resourcegroup"`, `"resourcegroup-with-subscriptionowner"`, `"subscription"`.
- [ ] `preferredLocation` is a comma-separated string of Azure region names.
- [ ] `estimatedDailyCostsUsd` is a non-negative number.

### 6. Platform Compatibility
- [ ] No hard-coded corporate network, specific DNS, or environment-specific blocks.
- [ ] Script works for on-site, online, and hybrid event formats.

---

## How to Run

1. Use `#tool:search` and `#tool:read` to locate and read each required file.
2. For each checklist item, read the relevant section and determine pass/fail.
3. Output the full checklist with ✅/❌ status.
4. Output a **Summary** section:
- Total: X/6 categories passing
- Blocking issues (❌ on categories 1–5 are blocking)
- Recommendations (non-blocking improvements)

Be strict. A missing `$schema` in lab-defaults.json or a wrong parameter name in deploy-lab.ps1 causes the platform to skip the script silently — flag these as blocking. A root-readme casing mismatch and an out-of-range `Get-MhhStableHash -Length` are also blocking (broken GitHub links / runtime failure respectively).
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Foundry CLM MicroHack — EMEA Platform Conventions

This workspace is the **Contract Lifecycle Management (CLM) agentic** microhack lab, built for the
**EMEA MicroHack platform** ([microsoft/MicroHack](https://github.com/microsoft/MicroHack)).
The platform renders a front-end UI, but **all resource provisioning comes from `labautomation/deploy-lab.ps1`**.
Without a working deployment script, no resources appear in the Azure portal — the platform is just a shiny front end.

## Mandatory Structure

```
labautomation/ ← exactly this name, no dashes
deploy-lab.ps1 ← platform entry point (optional but recommended)
lab-defaults.json ← platform configuration (required if folder exists)
README.md ← usage notes
challenges/ ← challenge instructions (Markdown)
walkthrough/ ← solutions
README.md ← hack intro, objectives, prerequisites
```

> This lab also ships `src/` (agent code), `images/`, and `docs/` for the CLM scenario.
> Those are additive — the platform contract above is what the platform enforces.

## deploy-lab.ps1 — Parameter Contract

The platform **skips the script** if the parameter block does not exactly match:

```powershell
param(
[Parameter(Mandatory=$true)]
[ValidateSet('subscription','resourcegroup','resourcegroup-with-subscriptionowner')]
[string]$DeploymentType,

[Parameter(Mandatory=$true)]
[string]$SubscriptionId,

[string]$ResourceGroupName = "",

[string[]]$PreferredLocation = @(),

[string[]]$AllowedEntraUserIds = @()
)
```

## Platform Guarantees (before your script runs)

- Az context is already set to `$SubscriptionId` — **do NOT call `Connect-AzAccount`**
- For `resourcegroup`/`resourcegroup-with-subscriptionowner`: the RG exists and your script has `Owner` — **do NOT call `New-AzResourceGroup`**
- For `subscription`: your script has `Owner` on the subscription; **you must create the RG yourself** using `Get-MhhStableHash` for deterministic naming
- `Az.Accounts` and `Az.Resources` modules are already imported

## lab-defaults.json — Required Shape

```json
{
"$schema": "https://raw.githubusercontent.com/microsoft/MicroHack/refs/heads/main/lab-defaults-schema.json",
"groups": ["M365-E5-Users"],
"deploymentType": "resourcegroup",
"labsPerSubscription": 8,
"preferredLocation": "swedencentral, westeurope, norwayeast",
"estimatedDailyCostsUsd": 5.0
}
```

- `deploymentType`: `"resourcegroup"` | `"resourcegroup-with-subscriptionowner"` | `"subscription"`
- `groups`: `["M365-E5-Users"]` for this hack — the CLM scenario needs M365 E5 (Teams publish, SharePoint corpus, proactive alerts). Use `[]` for Azure-only, or `["GHCPUsers"]` for a GitHub Copilot seat.
- `preferredLocation`: comma-separated regions, priority order — swedencentral first for gpt-5.4 + Claude Opus 4.8 availability
- `estimatedDailyCostsUsd`: per-user per-day cost for the lifecycle wizard (Foundry models + AI Search + App Insights)

## Returning Credentials to Users

Write a hashtable to the output stream — the platform captures it and shows it on the user's dashboard:

```powershell
@{ HackboxCredential = @{ name = "FoundryProjectEndpoint"; value = $endpoint; note = "AZURE_AI_PROJECT_ENDPOINT in .env" } }
```

## Platform Compatibility

The platform supports **on-site**, **online**, and **hybrid** delivery.
Do not hard-code corporate network or specific DNS assumptions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
---
description: "Use when creating, editing, or reviewing labautomation/deploy-lab.ps1, lab-defaults.json, or any PowerShell helper inside labautomation/. Enforces microsoft/MicroHack platform deployment conventions."
applyTo: "labautomation/**"
---

# Lab Automation Conventions (microsoft/MicroHack)

## deploy-lab.ps1 — Required Parameter Contract

The platform **silently skips** the script if the parameter block does not match exactly:

```powershell
param(
[Parameter(Mandatory=$true)]
[ValidateSet('subscription','resourcegroup','resourcegroup-with-subscriptionowner')]
[string]$DeploymentType,

[Parameter(Mandatory=$true)]
[string]$SubscriptionId,

[string]$ResourceGroupName = "",

[string[]]$PreferredLocation = @(),

[string[]]$AllowedEntraUserIds = @()
)
```

## Critical Platform Rules

**NEVER do these — they break platform integration:**

```powershell
# WRONG — platform already sets Az context
Connect-AzAccount

# WRONG — platform pre-creates the RG for resourcegroup deployments
New-AzResourceGroup -Name $ResourceGroupName ...
```

**For `subscription` deployments only** — you must create your own RG using a deterministic name:

```powershell
$stableHash = Get-MhhStableHash $AllowedEntraUserIds -Length 24
$effectiveResourceGroup = "lab-$stableHash"
New-AzResourceGroup -Name $effectiveResourceGroup -Location $effectiveLocation
```

## Resolving Effective Location

```powershell
$effectiveLocation = if ($PreferredLocation.Count -gt 0) { $PreferredLocation[0] } else { "swedencentral" }
```

## Deploying Resources

Reference templates relative to `$scriptPath`. This hack deploys the resource-group-scoped
module `infra/resources.bicep` (the same one `azd up` uses):

```powershell
$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
$template = Join-Path $scriptPath "infra/resources.bicep"
New-AzResourceGroupDeployment -ResourceGroupName $effectiveResourceGroup -TemplateFile $template -Verbose
```

## Returning Credentials to the User Dashboard

Write a hashtable to the output stream — the platform captures every one:

```powershell
@{ HackboxCredential = @{ name = "FoundryProjectEndpoint"; value = $endpoint; note = "AZURE_AI_PROJECT_ENDPOINT in .env" } }
```

Always return at minimum the resource group name so users can find their resources.

## lab-defaults.json — Required Shape

```json
{
"$schema": "https://raw.githubusercontent.com/microsoft/MicroHack/refs/heads/main/lab-defaults-schema.json",
"groups": [],
"deploymentType": "resourcegroup",
"labsPerSubscription": 4,
"preferredLocation": "swedencentral, westeurope, norwayeast",
"estimatedDailyCostsUsd": 12.0
}
```

- `$schema` is **required** — the platform validates against it
- `deploymentType`: `"resourcegroup"` | `"resourcegroup-with-subscriptionowner"` | `"subscription"`
- `groups`: `[]` for Azure-only; add `"GHCPUsers"` or `"M365-E5-Users"` as needed
- `preferredLocation`: comma-separated regions in priority order — list multiple for regional fallback
- `estimatedDailyCostsUsd`: cost per user per day; used in the lifecycle cost wizard

## Available Platform Helper Cmdlets

| Cmdlet | Use |
|--------|-----|
| `Get-MhhStableHash` | Deterministic per-user hash for resource naming in `subscription` mode |
| `Get-MhhLabUser` | Get Entra user details for `$AllowedEntraUserIds` |
| `Invoke-MhhDeploymentWithRegionFallback` | Deploy with automatic region fallback |
| `Test-MhhDeploymentFailureRetryable` | Check if a deployment error is transient |
Loading
Loading