|
| 1 | +# FSI-AgentGov Assessment Engine |
| 2 | + |
| 3 | +Automated governance assessment for Microsoft 365 Copilot Studio deployments in |
| 4 | +Financial Services. Collects tenant configuration via APIs, scores controls |
| 5 | +against zone-specific thresholds, and generates a pre-filled assessment with a |
| 6 | +focused manual questionnaire. |
| 7 | + |
| 8 | +## Architecture |
| 9 | + |
| 10 | +``` |
| 11 | +run-assessment.ps1 ← Orchestrator (PowerShell) |
| 12 | +├── collectors/ ← Data collection scripts (one per API surface) |
| 13 | +│ ├── Collect-PPAC.ps1 |
| 14 | +│ ├── Collect-Graph.ps1 |
| 15 | +│ ├── Collect-Purview.ps1 |
| 16 | +│ ├── Collect-SharePoint.ps1 |
| 17 | +│ └── Collect-Sentinel.ps1 |
| 18 | +├── engine/ ← Scoring & report generation (Python) |
| 19 | +│ ├── score.py |
| 20 | +│ └── report.py |
| 21 | +├── manifest/ |
| 22 | +│ └── controls.json ← 78-control definition manifest |
| 23 | +├── tests/ ← Automated tests |
| 24 | +│ ├── fixtures/ ← Synthetic test data |
| 25 | +│ ├── test_score.py |
| 26 | +│ └── test_report.py |
| 27 | +└── output/ ← Generated assessment artifacts |
| 28 | + ├── collected/ ← Raw collector JSON |
| 29 | + ├── scores.json |
| 30 | + ├── assessment-prefilled.md |
| 31 | + ├── manual-questionnaire.md |
| 32 | + └── assessment-summary.json |
| 33 | +``` |
| 34 | + |
| 35 | +## Prerequisites |
| 36 | + |
| 37 | +### PowerShell Modules |
| 38 | + |
| 39 | +| Module | Collector | Purpose | |
| 40 | +|--------|-----------|---------| |
| 41 | +| `Microsoft.PowerApps.Administration.PowerShell` | PPAC | Environment, DLP, role assignment data | |
| 42 | +| `Microsoft.Graph.Authentication` | Graph | Entra ID authentication | |
| 43 | +| `Microsoft.Graph.Identity.SignIns` | Graph | Conditional Access policies | |
| 44 | +| `Microsoft.Graph.Groups` | Graph | Security group enumeration | |
| 45 | +| `ExchangeOnlineManagement` | Purview | Audit log, retention, compliance policies | |
| 46 | +| `PnP.PowerShell` | SharePoint | Site permissions, sharing, grounding validation | |
| 47 | +| `Az.OperationalInsights` | Sentinel | Log Analytics workspace & connector status | |
| 48 | + |
| 49 | +### Python |
| 50 | + |
| 51 | +- **Python 3.10+** required |
| 52 | +- Install dependencies: |
| 53 | + |
| 54 | +```bash |
| 55 | +cd assessment |
| 56 | +pip install -r requirements.txt |
| 57 | +``` |
| 58 | + |
| 59 | +### Entra ID Permissions |
| 60 | + |
| 61 | +#### Interactive Mode |
| 62 | + |
| 63 | +Sign in as a Global Admin or a user with **all** of the following roles: |
| 64 | + |
| 65 | +| Role | Scope | |
| 66 | +|------|-------| |
| 67 | +| Power Platform Administrator | PPAC collector | |
| 68 | +| Compliance Administrator | Purview collector | |
| 69 | +| Security Reader | Graph collector | |
| 70 | +| SharePoint Administrator | SharePoint collector | |
| 71 | +| Log Analytics Reader | Sentinel collector | |
| 72 | + |
| 73 | +#### Service Principal Mode |
| 74 | + |
| 75 | +Register an Entra ID application with the following **application** permissions: |
| 76 | + |
| 77 | +| Permission | API | Collectors | |
| 78 | +|-----------|-----|------------| |
| 79 | +| `Policy.Read.All` | Microsoft Graph | Graph | |
| 80 | +| `Group.Read.All` | Microsoft Graph | Graph | |
| 81 | +| `Directory.Read.All` | Microsoft Graph | Graph | |
| 82 | +| `AuditLog.Read.All` | Microsoft Graph | Graph | |
| 83 | +| `Sites.Read.All` | Microsoft Graph | SharePoint | |
| 84 | +| `Files.Read.All` | Microsoft Graph | SharePoint | |
| 85 | +| Power Platform Admin API consent | Power Platform | PPAC | |
| 86 | + |
| 87 | +> **Note:** Some collectors (Purview, Sentinel) may still require interactive |
| 88 | +> authentication even in ServicePrincipal mode, depending on tenant |
| 89 | +> configuration. Use `-SkipCollectors` for those if needed. |
| 90 | +
|
| 91 | +## Quick Start |
| 92 | + |
| 93 | +### Interactive Mode (Recommended) |
| 94 | + |
| 95 | +```powershell |
| 96 | +.\run-assessment.ps1 ` |
| 97 | + -TenantId "00000000-0000-0000-0000-000000000000" ` |
| 98 | + -Zone 2 ` |
| 99 | + -AuthMode Interactive ` |
| 100 | + -CustomerName "Contoso Financial" ` |
| 101 | + -SubscriptionId "00000000-0000-0000-0000-000000000001" ` |
| 102 | + -ResourceGroup "rg-sentinel" ` |
| 103 | + -WorkspaceName "sentinel-workspace" |
| 104 | +``` |
| 105 | + |
| 106 | +### Service Principal Mode |
| 107 | + |
| 108 | +```powershell |
| 109 | +$secret = Read-Host -AsSecureString "Client Secret" |
| 110 | +
|
| 111 | +.\run-assessment.ps1 ` |
| 112 | + -TenantId "00000000-0000-0000-0000-000000000000" ` |
| 113 | + -Zone 3 ` |
| 114 | + -AuthMode ServicePrincipal ` |
| 115 | + -ClientId "00000000-0000-0000-0000-000000000002" ` |
| 116 | + -ClientSecret $secret ` |
| 117 | + -CustomerName "Contoso Financial" ` |
| 118 | + -ApprovedSitesCsv ".\approved-sites.csv" ` |
| 119 | + -SubscriptionId "00000000-0000-0000-0000-000000000001" ` |
| 120 | + -ResourceGroup "rg-sentinel" ` |
| 121 | + -WorkspaceName "sentinel-workspace" |
| 122 | +``` |
| 123 | + |
| 124 | +### Skipping Collectors |
| 125 | + |
| 126 | +Skip one or more collectors when their prerequisites aren't available: |
| 127 | + |
| 128 | +```powershell |
| 129 | +.\run-assessment.ps1 ` |
| 130 | + -TenantId "..." ` |
| 131 | + -Zone 2 ` |
| 132 | + -AuthMode Interactive ` |
| 133 | + -CustomerName "Contoso Financial" ` |
| 134 | + -SkipCollectors @("Sentinel", "Purview") |
| 135 | +``` |
| 136 | + |
| 137 | +> When a collector is skipped, controls that depend on its data are scored with |
| 138 | +> **confidence: low** and flagged for manual review. |
| 139 | +
|
| 140 | +### Custom Output Directory |
| 141 | + |
| 142 | +```powershell |
| 143 | +.\run-assessment.ps1 ... -OutputDir "C:\Assessments\contoso-2026-03" |
| 144 | +``` |
| 145 | + |
| 146 | +## Zones |
| 147 | + |
| 148 | +The FSI-AgentGov framework defines three deployment zones with increasing |
| 149 | +governance requirements: |
| 150 | + |
| 151 | +| Zone | Name | Description | |
| 152 | +|------|------|-------------| |
| 153 | +| 1 | **Standard** | Internal agents, low-risk data, minimal regulatory overlap | |
| 154 | +| 2 | **Sensitive** | Customer-facing or PII-handling agents, moderate compliance | |
| 155 | +| 3 | **Regulated** | Agents in regulated workloads (banking, insurance, capital markets) | |
| 156 | + |
| 157 | +Higher zones require more checks to pass per control, resulting in higher |
| 158 | +maturity thresholds. A zone-3 assessment is the most stringent. |
| 159 | + |
| 160 | +## Output Files |
| 161 | + |
| 162 | +| File | Format | Description | |
| 163 | +|------|--------|-------------| |
| 164 | +| `output/collected/*.json` | JSON | Raw data snapshots from each collector | |
| 165 | +| `output/scores.json` | JSON | Per-control scores, check results, confidence, and evidence | |
| 166 | +| `output/assessment-prefilled.md` | Markdown | Pre-filled assessment report organized by pillar and control | |
| 167 | +| `output/manual-questionnaire.md` | Markdown | Interview questions for controls requiring manual validation | |
| 168 | +| `output/assessment-summary.json` | JSON | Machine-readable summary for dashboards and CI integration | |
| 169 | + |
| 170 | +## Maturity Scale |
| 171 | + |
| 172 | +Each control receives a maturity score from 0–4: |
| 173 | + |
| 174 | +| Score | Level | Description | |
| 175 | +|-------|-------|-------------| |
| 176 | +| 0 | **Not Implemented** | Control is absent or all checks failed | |
| 177 | +| 1 | **Baseline** (25%) | Minimal implementation — meets zone-1 threshold | |
| 178 | +| 2 | **Recommended** (50%) | Standard compliance — meets zone-2 threshold | |
| 179 | +| 3 | **Advanced** (75%) | Strong implementation with enhanced protections | |
| 180 | +| 4 | **Fully Regulated** (100%) | Complete implementation — meets zone-3 threshold | |
| 181 | + |
| 182 | +A control's maturity score is determined by comparing the number of passing |
| 183 | +checks against the zone-specific threshold in the controls manifest. If the |
| 184 | +passing count is below the minimum, the score is 0 (Not Implemented). |
| 185 | + |
| 186 | +## Confidence Levels |
| 187 | + |
| 188 | +Each control score includes a confidence indicator: |
| 189 | + |
| 190 | +| Level | Meaning | |
| 191 | +|-------|---------| |
| 192 | +| **High** | All required API calls returned valid data | |
| 193 | +| **Medium** | Some data sources returned partial results or warnings | |
| 194 | +| **Low** | Required data sources were unavailable, null, or errored | |
| 195 | + |
| 196 | +Low-confidence scores are highlighted in the assessment report and |
| 197 | +automatically added to the manual questionnaire for validation. |
| 198 | + |
| 199 | +## Collector Exit Codes |
| 200 | + |
| 201 | +| Code | Meaning | Orchestrator Behavior | |
| 202 | +|------|---------|----------------------| |
| 203 | +| 0 | **Success** | All data collected cleanly | |
| 204 | +| 1 | **Partial** | Some API calls failed; partial data saved | Logged as warning; run continues | |
| 205 | +| 2 | **Failure** | Collector could not produce usable data | Logged as error; run continues | |
| 206 | + |
| 207 | +The orchestrator never halts on collector failures. Downstream scoring handles |
| 208 | +missing data by lowering confidence. |
| 209 | + |
| 210 | +## Running Tests |
| 211 | + |
| 212 | +```bash |
| 213 | +cd assessment |
| 214 | +pip install -r requirements.txt |
| 215 | +pytest tests/ -v |
| 216 | +``` |
| 217 | + |
| 218 | +### Test Coverage |
| 219 | + |
| 220 | +| File | Tests | Focus | |
| 221 | +|------|-------|-------| |
| 222 | +| `tests/test_score.py` | 7 | Zone thresholds, maturity scoring, confidence, summaries | |
| 223 | +| `tests/test_report.py` | 4 | Output file generation, Markdown structure, JSON schema | |
| 224 | + |
| 225 | +### Test Fixtures |
| 226 | + |
| 227 | +Test fixtures in `tests/fixtures/` provide synthetic tenant data for |
| 228 | +deterministic, offline testing: |
| 229 | + |
| 230 | +| Fixture | Contents | |
| 231 | +|---------|----------| |
| 232 | +| `controls_subset.json` | 5-control manifest (controls 1.1, 1.3, 2.1, 3.1, 4.4) | |
| 233 | +| `ppac.json` | Power Platform environment, DLP, and role assignment data | |
| 234 | +| `graph.json` | Conditional Access policies and Entra ID configuration | |
| 235 | +| `purview.json` | Audit log config, retention policies | |
| 236 | +| `sharepoint.json` | Site inventory, sharing settings, grounding scope | |
| 237 | +| `sentinel.json` | Log Analytics workspace and connector status | |
| 238 | +| `expected_scores.json` | Expected zone-2 scoring output for validation | |
| 239 | + |
| 240 | +## Idempotency |
| 241 | + |
| 242 | +Running the orchestrator multiple times with the same parameters cleanly |
| 243 | +overwrites the output directory. No append-only files or cumulative state is |
| 244 | +maintained between runs. |
| 245 | + |
| 246 | +## Troubleshooting |
| 247 | + |
| 248 | +### "Python 3 is required but was not found" |
| 249 | + |
| 250 | +Ensure Python 3.10+ is installed and available as `python3`, `python`, or `py` |
| 251 | +on your PATH. |
| 252 | + |
| 253 | +### Collector authentication errors |
| 254 | + |
| 255 | +- **Interactive mode:** Ensure you have the required admin roles and that your |
| 256 | + browser session isn't blocked by Conditional Access. |
| 257 | +- **ServicePrincipal mode:** Verify the app registration has the correct API |
| 258 | + permissions and that admin consent has been granted. |
| 259 | + |
| 260 | +### Missing Sentinel parameters |
| 261 | + |
| 262 | +If you don't use Microsoft Sentinel, skip its collector: |
| 263 | + |
| 264 | +```powershell |
| 265 | +.\run-assessment.ps1 ... -SkipCollectors @("Sentinel") |
| 266 | +``` |
| 267 | + |
| 268 | +### Partial collector results |
| 269 | + |
| 270 | +When a collector returns exit code 1, check the `_metadata.warnings` array in |
| 271 | +its output JSON for details on which API calls failed. |
0 commit comments