Skip to content
Open
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
137 changes: 137 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"name": "Healthcare AI Model Evaluator",
"dockerComposeFile": "docker-compose.devcontainer.yml",
"service": "devcontainer",
"workspaceFolder": "/workspace",

"features": {
"ghcr.io/devcontainers/features/dotnet:2": {
"version": "8.0",
"installUsingApt": true
},
"ghcr.io/devcontainers/features/python:1": {
"version": "3.11"
},
"ghcr.io/devcontainers/features/node:1": {
"version": "23"
},
"ghcr.io/devcontainers/features/azure-cli:1": {
"version": "latest"
},
"ghcr.io/azure/azure-dev/azd:0": {
"version": "latest"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {
"version": "latest",
"dockerDashComposeVersion": "v2"
},
"ghcr.io/devcontainers/features/git:1": {
"version": "latest"
}
},

"customizations": {
"vscode": {
"extensions": [
"ms-dotnettools.csharp",
"ms-dotnettools.csdevkit",
"ms-python.python",
"ms-python.vscode-pylance",
"ms-azuretools.vscode-azurefunctions",
"ms-azuretools.vscode-docker",
"ms-vscode.azurecli",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"ms-vscode.vscode-typescript-next",
"ms-azuretools.vscode-bicep",
"GitHub.copilot",
"GitHub.copilot-chat"
],
"settings": {
"python.defaultInterpreterPath": "/usr/local/bin/python",
"python.formatting.provider": "black",
"python.linting.enabled": true,
"python.linting.pylintEnabled": true,
"python.testing.pytestEnabled": true,
"python.testing.unittestEnabled": false,
"python.analysis.typeCheckingMode": "basic",
"[python]": {
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "explicit"
}
},
"[csharp]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"dotnet.defaultSolution": "backend/MedBench.sln",
"files.exclude": {
"**/bin": true,
"**/obj": true,
"**/__pycache__": true,
"**/node_modules": true
},
"azureFunctions.pythonVenv": ".venv",
"azureFunctions.projectRuntime": "~4",
"azureFunctions.projectLanguage": "Python"
}
}
},

"forwardPorts": [
5000,
5173,
7071,
10000,
10001,
10002,
27017
],

"portsAttributes": {
"5000": {
"label": ".NET Backend API",
"onAutoForward": "notify"
},
"5173": {
"label": "React Frontend (Vite)",
"onAutoForward": "notify"
},
"7071": {
"label": "Azure Functions",
"onAutoForward": "notify"
},
"10000": {
"label": "Azurite Blob",
"onAutoForward": "silent"
},
"10001": {
"label": "Azurite Queue",
"onAutoForward": "silent"
},
"10002": {
"label": "Azurite Table",
"onAutoForward": "silent"
},
"27017": {
"label": "MongoDB (CosmosDB emulator)",
"onAutoForward": "silent"
}
},

"postCreateCommand": "bash .devcontainer/post-create.sh",

"remoteUser": "vscode",

"mounts": [
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.azure,target=/home/vscode/.azure,type=bind,consistency=cached"
]
}
29 changes: 29 additions & 0 deletions .github/workflows/template-validation.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Template Validation
on:
workflow_dispatch:
push:

permissions:
contents: read
id-token: write
pull-requests: write

jobs:
template_validation_job:
runs-on: ubuntu-latest
name: template validation
steps:
- uses: actions/checkout@v4

- uses: microsoft/template-validation-action@Latest
id: validation
env:
AZURE_CLIENT_ID: ${{ vars.AZURE_CLIENT_ID }}
AZURE_TENANT_ID: ${{ vars.AZURE_TENANT_ID }}
AZURE_SUBSCRIPTION_ID: ${{ vars.AZURE_SUBSCRIPTION_ID }}
AZURE_ENV_NAME: ${{ vars.AZURE_ENV_NAME }}
AZURE_LOCATION: ${{ vars.AZURE_LOCATION }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: print result
run: cat ${{ steps.validation.outputs.resultFile }}
119 changes: 116 additions & 3 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,63 @@ azd env set ENABLE_ACS false

Now that your environment is configured, you can deploy all necessary resources and infrastructure for the Healthcare AI Model Evaluator.

#### IP Filtering & Security Configuration

**By default, the deployment is secure-by-default** and will prompt you to configure IP filtering to protect the web application:

- **During first deployment**, you'll be prompted to enter an IP address that can access the web application
- **Your current public IP** is automatically detected and suggested as the default (using preprovision hooks)
- **Only specified IPs** can access the web application - all other access is blocked at the Container App ingress level
- **Backend data services** (Cosmos DB, Storage) use public endpoints but are secured via managed identity authentication and connection strings
- **IP filtering applies only to the Container App** - Azure Functions, Storage, and Cosmos DB are secured through Azure's service-to-service authentication and managed identities

**Managing IP Access:**

```sh
# View current IP filtering settings
azd env get-value ALLOWED_WEB_IP
azd env get-value ENABLE_WEB_IP_FILTERING

# Add or update allowed IPs (comma-delimited CIDR format)
azd env set ALLOWED_WEB_IP "89.144.197.27/32,203.0.113.1/32"

# Disable IP filtering entirely (not recommended for production)
azd env set ENABLE_WEB_IP_FILTERING false

# Open to the entire internet
azd env set ENABLE_WEB_IP_FILTERING false
azd env set ALLOWED_WEB_IP ""

# Re-deploy with new settings
azd up
```

> [!WARNING]
> **Opening to Internet**: Setting `ENABLE_WEB_IP_FILTERING=false` removes all IP restrictions and allows public internet access to your application.

**Quick Commands for Common Scenarios:**

```sh
# Development: Open to internet (use only for testing)
azd env set ENABLE_WEB_IP_FILTERING false
azd up

# Production: Lock down to your office IP
azd env set ENABLE_WEB_IP_FILTERING true
azd env set ALLOWED_WEB_IP "your.office.ip.address/32"
azd up

# Multiple locations: Home + Office access
azd env set ALLOWED_WEB_IP "home.ip.address/32,office.ip.address/32"
azd up
```

> [!WARNING]
> **Portal Changes**: Any IP filtering changes made directly in the Azure portal will be overwritten by `azd up`. Always use the azd environment variables to manage IP access.

> [!TIP]
> **Multiple Locations**: Use comma-delimited CIDR notation to allow access from multiple locations: `"home.ip.address/32,office.ip.address/32,vpn.range.address/24"`

> [!IMPORTANT]
> **Security Consideration**: For production deployments in healthcare environments, consider integrating with your existing Azure Front Door after deployment. See the [Security Configuration](#security-configuration) section for Front Door integration steps.

Expand Down Expand Up @@ -200,17 +257,41 @@ az functionapp list --output table

# Get your application URL (frontend and API served from same endpoint)
echo "Application URL: $(azd env get-value API_BASE_URL)"
echo "Frontend: $(azd env get-value API_BASE_URL)/webapp"
echo "Frontend: $(azd env get-value API_BASE_URL)
echo "API: $(azd env get-value API_BASE_URL)/api"
```

## Post-Deployment Setup

### Create First Admin User

After successful deployment, create your first admin user to access the application:

```bash
# Run the admin user creation script
./infra/scripts/create-admin-user.sh
```

The script will prompt you for:
- **Admin email address**: Used for login
- **Admin password**: Must meet complexity requirements (8+ characters, 3 of 4 character types)
- **Admin full name**: Display name in the application

Once created, you can:
1. Navigate to your application URL: `$(azd env get-value API_BASE_URL)/webapp`
2. Click "Sign in with Password"
3. Use the email/password you just created
4. Access the admin panel to create additional users

> **Note**: This script only needs to be run once. Additional users can be created through the web interface by admin users.

---

## Architecture Overview

### Components

**Frontend**: React-based web application served from the .NET API at `/webapp`
**Frontend**: React-based web application served from the .NET API at `/`
- User interface for model evaluation management
- Authentication via Entra ID

Expand Down Expand Up @@ -433,7 +514,39 @@ az network front-door routing-rule create \
azd up
```

4. **Function Deployment Failures**
4. **Cannot Access the Application (403 Forbidden)**
> This typically means your IP address is not in the allowed list

Check your current IP and update the allowed list:
```bash
# Check what IP you're accessing from
curl ifconfig.me

# View current filtering settings
azd env get-value ENABLE_WEB_IP_FILTERING
azd env get-value ALLOWED_WEB_IP

# Update with your current IP
azd env set ALLOWED_WEB_IP "$(curl -s ifconfig.me)/32"
azd up

# Or temporarily disable for troubleshooting (development only)
azd env set ENABLE_WEB_IP_FILTERING false
azd up
```

5. **IP Filtering Not Working as Expected**
```bash
# Verify Container App ingress rules in Azure Portal
az containerapp ingress show \
--name "api-$(azd env get-value AZURE_ENV_NAME)" \
--resource-group "$(azd env get-value AZURE_RESOURCE_GROUP)"

# Check if changes were applied (restart may be needed)
azd up
```

6. **Function Deployment Failures**
```bash
# Check Docker is running
docker info
Expand Down
6 changes: 4 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
<PackageVersion Include="Azure.AI.Inference" Version="1.0.0-beta.3" />
<PackageVersion Include="Azure.AI.OpenAI" Version="2.1.0" />
<PackageVersion Include="Azure.Identity" Version="1.11.4" />
<PackageVersion Include="Azure.Security.KeyVault.Secrets" Version="4.6.0" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.19.1" />
<PackageVersion Include="Azure.Communication.Email" Version="1.1.0-beta.2" />
<PackageVersion Include="coverlet.collector" Version="6.0.0" />
<PackageVersion Include="DotEnv.Net" Version="3.2.1" />
<PackageVersion Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.3.0" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.0" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.37.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.2" />
<PackageVersion Include="Microsoft.Identity.Web" Version="2.16.1" />
<PackageVersion Include="Microsoft.Identity.Web.UI" Version="2.16.1" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,20 @@ For a complete overview of the Healthcare AI Model Evaluator platform, refer to

Deploy the complete Healthcare AI Model Evaluator platform with a single command using Azure Developer CLI (azd).

```
```bash
azd up
```

### First-time Setup

After deployment, create your first admin user by running:

```bash
./infra/scripts/create-admin-user.sh
```

This script will prompt you for admin credentials and create the user in the database. The admin user can then log in and manage other users through the web interface.

## Local Development

### Frontend setup
Expand Down Expand Up @@ -127,5 +137,8 @@ Before using this tool, verify that:
3. You have the legal right, authority, and ownership to use the data, and its use here does not violate any contractual, licensing, or proprietary restrictions.
4. All downstream uses of the data remain compliant with relevant laws and regulations.

>[!IMPORTANT]
Dataset added to the tool are set to auto delete 180 days after being added. This setting can be extended for each data set.

>[!IMPORTANT]
> Microsoft products and services (1) are not designed, intended, or made available as a medical device, and (2) are not designed or intended to replace professional medical advice, diagnosis, treatment, or judgment and should not be used as a substitute for professional medical advice, diagnosis, treatment, or judgment. Customers and partners are responsible for ensuring that their solutions comply with all applicable laws and regulations.
Loading
Loading