Skip to content

Commit fd8cbd4

Browse files
committed
docs: Add demo script and run instructions
1 parent decf7d2 commit fd8cbd4

File tree

2 files changed

+139
-0
lines changed

2 files changed

+139
-0
lines changed

AIGovHub/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,19 @@ docker compose up --build
230230
| API Docs | http://localhost:8000/docs |
231231
| Metrics | http://localhost:8000/api/v1/metrics |
232232

233+
### Run a Demo Scenario
234+
235+
We include a python script that walks through a full governance workflow (Register -> Link Lineage -> Enforce Policy).
236+
237+
1. Ensure the stack is running (`docker compose up`)
238+
2. Run the script:
239+
240+
```bash
241+
cd AIGovHub
242+
pip install httpx
243+
python examples/demo_flow.py
244+
```
245+
233246
---
234247

235248
## Technology Stack

AIGovHub/examples/demo_flow.py

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
2+
import asyncio
3+
import httpx
4+
import json
5+
import sys
6+
from datetime import datetime
7+
8+
# Configuration
9+
API_URL = "http://localhost:8000/api/v1"
10+
# For a real demo with auth, we would need to login first.
11+
# Assuming default dev setup might allow open access or we mock a token if RBAC is strict.
12+
# Based on existing code, some endpoints might be protected.
13+
# Let's assume we can use a hardcoded admin token or similar if needed,
14+
# but for now we'll try to follow the likely open dev paths or basic auth patterns.
15+
# Note: In a fresh dev setup, we might need to create a user first.
16+
17+
print(f"🚀 Starting AI Governance Hub Demo against {API_URL}...\n")
18+
19+
async def run_demo():
20+
async with httpx.AsyncClient(base_url=API_URL, timeout=10.0) as client:
21+
22+
# 1. Check Health
23+
print("[1] Checking API Health...")
24+
try:
25+
resp = await client.get("/")
26+
print(f" ✅ API is up: {resp.json()['message']}")
27+
except Exception as e:
28+
print(f" ❌ API Not Reachable: {e}")
29+
print(" Make sure 'docker compose up' is running!")
30+
sys.exit(1)
31+
32+
# 2. Register a High-Risk Model
33+
print("\n[2] Registering 'Credit Risk Scoring v1' Model...")
34+
model_payload = {
35+
"name": f"Credit Risk Scoring {datetime.now().strftime('%H%M%S')}",
36+
"owner": "Finance-Risk-Team",
37+
"description": "Predicts loan default probability for retail customers.",
38+
"risk_level": "high",
39+
"domain": "finance",
40+
"data_sensitivity": "pii",
41+
"data_classification": "confidential",
42+
"monitor_plan": "Monthly drift checks"
43+
}
44+
resp = await client.post("/models/", json=model_payload)
45+
if resp.status_code not in [200, 201]:
46+
print(f" ❌ Failed: {resp.text}")
47+
return
48+
model = resp.json()
49+
model_id = model['id']
50+
print(f" ✅ Created Model ID {model_id}: {model['name']}")
51+
52+
# 3. Register a Sensitive Dataset
53+
print("\n[3] Registering 'Customer Transaction Data 2024' Dataset...")
54+
dataset_payload = {
55+
"name": "Customer Transactions 2024",
56+
"source_system": "DataLake_Finance",
57+
"data_sensitivity": "pii",
58+
"data_classification": "restricted"
59+
}
60+
resp = await client.post("/datasets/", json=dataset_payload)
61+
dataset = resp.json()
62+
dataset_id = dataset['id']
63+
print(f" ✅ Created Dataset ID {dataset_id}: {dataset['name']} ({dataset['data_sensitivity']})")
64+
65+
# 4. Link Dataset to Model (Lineage)
66+
print("\n[4] Linking Dataset to Model...")
67+
link_payload = {
68+
"dataset_id": dataset_id,
69+
"dataset_type": "training"
70+
}
71+
resp = await client.post(f"/models/{model_id}/datasets/", json=link_payload)
72+
print(" ✅ Lineage Established")
73+
74+
# 5. Create a Policy (Block High Risk without Approval)
75+
print("\n[5] Creating Policy: 'Block Unapproved High Risk'...")
76+
policy_payload = {
77+
"name": f"High Risk Guardrail {datetime.now().strftime('%H%M')}",
78+
"description": "Blocks deployment of high-risk models without human approval",
79+
"scope": "global",
80+
"condition_type": "block_high_risk_without_approval",
81+
"is_active": True
82+
}
83+
# Note: Policy endpoint might differ slightly based on implementation, adjusting if needed
84+
# Assuming /policies/ based on previous browsing
85+
resp = await client.post("/policies/", json=policy_payload)
86+
if resp.status_code in [200, 201]:
87+
print(f" ✅ Policy Created: {resp.json()['name']}")
88+
else:
89+
print(f" ⚠️ Could not create policy (might already exist): {resp.status_code}")
90+
91+
# 6. Attempt Invalid Status Change (Simulating Policy Violation)
92+
print("\n[6] Attempting to approve model WITHOUT missing notes...")
93+
# Assuming we try to set to 'approved' directly
94+
# The prompt mentioned "Human Approvals" requiring notes.
95+
status_payload = {
96+
"status": "approved",
97+
"reason": "Rushing into production!"
98+
# Missing "approval_notes"
99+
}
100+
resp = await client.patch(f"/models/{model_id}/compliance-status", json=status_payload)
101+
if resp.status_code == 400 or resp.status_code == 403:
102+
print(f" ✅ Request Blocked as Expected! Code: {resp.status_code}")
103+
print(f" Reason: {resp.json()['detail']}")
104+
else:
105+
print(f" ❌ Unexpected success or error: {resp.status_code} {resp.text}")
106+
107+
# 7. Valid Approval (Human-in-the-Loop)
108+
print("\n[7] Approving model WITH required notes...")
109+
status_payload_valid = {
110+
"status": "approved",
111+
"reason": "Passed all risk checks.",
112+
"approval_notes": "Reviewed by CISO on 2024-01-01. Mitigation controls in place."
113+
}
114+
resp = await client.patch(f"/models/{model_id}/compliance-status", json=status_payload_valid)
115+
if resp.status_code == 200:
116+
updated_model = resp.json()
117+
print(f" ✅ Model Approved!")
118+
print(f" Approver ID: {updated_model.get('approved_by_user_id')}")
119+
print(f" Notes: {updated_model.get('approval_notes')}")
120+
else:
121+
print(f" ❌ Failed to approve: {resp.status_code} {resp.text}")
122+
123+
print("\n✨ Demo Completed Successfully! View your model in the Dashboard.")
124+
125+
if __name__ == "__main__":
126+
asyncio.run(run_demo())

0 commit comments

Comments
 (0)