| name | generate-report |
| description | Generate an interactive, self-contained HTML dashboard displaying SFI-TI3.2.2 tenant isolation violations for a service, org, or alias -- includes filtering, sorting, severity coding, TSG links, S360 deep links. |
| lastReviewed | 2026-04-30T00:00:00.000Z |
Generate Tenant Isolation Violation Report
Generate an interactive, self-contained HTML dashboard that displays all SFI-TI3.2.2 tenant
isolation violations for a given service, org, or alias. The report opens in the default browser
and includes filtering, sorting, color-coded severity, TSG links, and S360 deep links.
Trigger detection
Activate when the user says:
- "generate report" / "create dashboard" / "show violations report"
- "HTML report" / "violation dashboard" / "export violations"
- "tenant isolation report" / "create violation report"
- "generate TI report" / "show tenant isolation dashboard"
- "build HTML dashboard" / "S360 TI report"
- "generate SFI-TI3.2.2 report" / "export tenant isolation violations"
Step 1 — Accept violation data
The input is structured violation data from the fetch-violations skill, typically passed
by the violation-triager skill. Each violation object is a normalized flat record
derived from the MCP response (flattened from CustomDimensions and S360Dimensions):
Title — Violation type (one of 9 titles, see Step 2)
TargetId — S360 target ID (service-level)
AppId — Application GUID (from CustomDimensions; empty for connector items)
AppDisplayName — App name (from CustomDimensions; empty for connector items)
AppHomeTenantId — Home tenant GUID
cloudType — "Public", "Fairfax", "Mooncake"
SLAState — "OnTime" or "OutOfSla"
CurrentDueDate — Current due date
CurrentETA — ETA set by action owner
ActionOwnerAlias — Action owner alias (from S360Dimensions)
ADOWorkItemHTMLUrl — ADO work item link (from S360Dimensions)
URL — TSG / remediation link
KpiActionItemId — Unique action item identifier
The remediationCategory, severity, and tsgLink fields are derived by the
skill at classification time (Step 2), not from the MCP response.
If no violation data is provided (or the array is empty), respond:
"No violation data provided. Please run fetch-violations first to retrieve violations,
then pass the results to this skill."
Step 2 — Classify violations for display
For each violation, compute three derived fields:
Remediation Category
Map ViolationTitle to a remediation category:
| ViolationTitle | Remediation Category |
|---|
AAD Entra Apps in Prod Tenants using certificates in Non-Prod Tenant | Cert Rehoming |
AAD Entra Apps cloud mismatches with Cert Cloud | Cert Rehoming |
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud auth scenarios | FIC Setup |
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud 1P scenarios | FIC Setup |
1pApp certs Tenant mismatches the Tenant of the Security Group | SG Update |
AAD Entra apps with cross-tenant violations | Cross-Tenant |
Connector domain OWNER should not use shared subjectName for authentication across tenant | Connector |
Connector domain CONSUMER should not use shared subjectName for authentication across tenant | Connector |
1P App with invalid security group | SG Update |
Severity Color
Determine severity based on remediation complexity:
- Green (Autofix eligible): Violations where an automated SG update can resolve them
1P App with invalid security group
- Yellow (Guidance available): Violations with clear TSG guidance but requiring manual owner action
AAD Entra Apps in Prod Tenants using certificates in Non-Prod Tenant
AAD Entra Apps cloud mismatches with Cert Cloud
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud auth scenarios
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud 1P scenarios
1pApp certs Tenant mismatches the Tenant of the Security Group — requires a follow-up SG-vs-cert decision
- Red (Complex remediation): Multi-step or cross-team coordination required
AAD Entra apps with cross-tenant violations
Connector domain OWNER should not use shared subjectName for authentication across tenant
Connector domain CONSUMER should not use shared subjectName for authentication across tenant
TSG Link
Map ViolationTitle to the correct aka.ms troubleshooting guide:
| ViolationTitle | TSG Link |
|---|
AAD Entra Apps in Prod Tenants using certificates in Non-Prod Tenant | https://aka.ms/entraQ4 |
AAD Entra Apps cloud mismatches with Cert Cloud | https://aka.ms/entraQ5 |
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud auth scenarios | https://aka.ms/entraQ5 |
AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud 1P scenarios | https://aka.ms/entraQ5 |
1pApp certs Tenant mismatches the Tenant of the Security Group | https://aka.ms/entraQ6 |
AAD Entra apps with cross-tenant violations | https://aka.ms/entraQ7 |
Connector domain OWNER should not use shared subjectName for authentication across tenant | https://aka.ms/entraQ8 |
Connector domain CONSUMER should not use shared subjectName for authentication across tenant | https://aka.ms/entraQ8 |
1P App with invalid security group | https://aka.ms/entraQ9 |
Store the classified results as violations[] with added fields:
remediationCategory, severity (green/yellow/red), tsgLink.
Compute summary:
total = violations.length
autofixCount = count where severity == 'green'
guidanceCount = count where severity == 'yellow'
complexCount = count where severity == 'red'
uniqueApps = distinct AppId count
Step 3 — Generate the HTML report
Write a complete, self-contained HTML file to:
.\s360-ti322-report-{YYYYMMDD}-{HHmmss}.html
The violations array must be serialized as JSON and embedded as a JS variable.
Use these placeholder substitutions:
{TARGET_LABEL} → filter description (alias/service/org) or "All"
{GENERATED} → current datetime ISO string
{VIOLATIONS_JSON} → JSON.stringify(violations) — each item contains all original
fields plus remediationCategory, severity, tsgLink
{TOTAL} → total
{AUTOFIX_COUNT} → autofixCount
{GUIDANCE_COUNT} → guidanceCount
{COMPLEX_COUNT} → complexCount
{UNIQUE_APPS} → uniqueApps
HTML template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>SFI-TI 3.2.2 Tenant Isolation — Violation Report</title>
<style>
:root {
--bg: #f4f6f9;
--surface: #ffffff;
--surface2: #f0f2f5;
--border: #dfe3ea;
--header-bg: #1b2a4a;
--header-text: #ffffff;
--text: #1e293b;
--muted: #64748b;
--accent: #3b82f6;
--accent-hover: #2563eb;
--green: #16a34a;
--green-bg: rgba(22,163,74,.08);
--green-border: rgba(22,,,.);
: ;
: (,,,.);
: (,,,.);
: ;
: (,,,.);
: (,,,.);
: ;
: (,,,.), (,,,.);
: -apple-system, BlinkMacSystemFont, , system-ui, sans-serif;
}
*, *, * { : border-box; : ; : ; }
{
: (--bg);
: (--text);
: (--font);
: ;
: ;
}
{
: (--header-bg);
: (--header-text);
: ;
: flex;
: wrap;
: center;
: ;
}
{
: ;
: ;
: -;
}
{
: .;
: .;
: flex;
: ;
: wrap;
}
{ : nowrap; }
{
: ;
: auto;
: ;
}
{
: grid;
: (auto-fit, (, fr));
: ;
: ;
}
{
: (--surface);
: solid (--border);
: (--radius);
: ;
: (--shadow);
: transform ., box-shadow .;
}
{
: (-);
: (,,,.);
}
{
: ;
: ;
: ;
}
{
: (--muted);
: .;
: uppercase;
: .;
: ;
}
{ : (--accent); }
{ : (--green); }
{ : (--yellow); }
{ : (--red); }
{ : (--muted); }
{ : solid (--green); }
{ : solid (--yellow); }
{ : solid (--red); }
{ : solid (--accent); }
{
: (--surface);
: solid (--border);
: (--radius);
: ;
: ;
: flex;
: wrap;
: ;
: center;
: (--shadow);
}
{
: .;
: (--muted);
: ;
: uppercase;
: .;
}
,
{
: (--surface2);
: solid (--border);
: (--text);
: ;
: ;
: .;
: (--font);
: none;
: border-color .;
}
,
{
: (--accent);
: (,,,.);
}
{ : ; }
{
: auto;
: .;
: (--muted);
: ;
}
{
: (--surface);
: solid (--border);
: (--radius);
: hidden;
: (--shadow);
}
{
: auto;
: ;
: auto;
}
{
: ;
: collapse;
: .;
}
{ : sticky; : ; : ; }
{
: (--header-bg);
: (--header-text);
: ;
: left;
: ;
: .;
: uppercase;
: .;
: nowrap;
: pointer;
: none;
: solid (,,,.);
}
{ : ; }
{ : ; : .; : .; }
{ : ; }
{
: ;
: solid (--border);
: middle;
}
{ : none; }
{ : none; }
() { : (,,,.); }
{ : (--green); }
{ : (--yellow); }
{ : (--red); }
{ : inset (--green); }
{ : inset (--yellow); }
{ : inset (--red); }
{
: inline-block;
: ;
: ;
: ;
: middle;
}
{ : (--green); }
{ : (--yellow); }
{ : (--red); }
{
: inline-block;
: ;
: ;
: .;
: ;
: nowrap;
}
{ : (--green-bg); : (--green); : solid (--green-border); }
{ : (--yellow-bg); : (--yellow); : solid (--yellow-border); }
{ : (--red-bg); : (--red); : solid (--red-border); }
{ : (,,,.); : (--accent); : solid (,,,.); }
{ : (,,,.); : (--muted); : solid (,,,.); }
,
{
: (--accent);
: none;
: .;
: ;
: nowrap;
}
,
{ : underline; }
{
: .;
: ;
: ;
: break-word;
}
{ : ; }
{
: inline-block;
: .;
: (--muted);
: (--surface2);
: ;
: ;
}
{
: .;
: ;
: ;
: break-word;
}
{
: none;
: center;
: ;
: (--muted);
: .;
}
{
: (--muted);
: .;
: ;
: center;
: ;
}
print {
{ : ; : ; }
{ : ; -webkit-: exact; : exact; }
{ : none; }
{ : none; : visible; }
{ : avoid; }
{ : none ; }
{ : (--accent) ; }
}
(: ) {
{ : ; }
{ : ; }
{ : (, fr); }
{ : ; }
}
🛡️ SFI-TI 3.2.2 Tenant Isolation — Violation Report
Target: {TARGET_LABEL}
Generated: {GENERATED}
{TOTAL}
Total Violations
{AUTOFIX_COUNT}
✅ Autofix Eligible
{GUIDANCE_COUNT}
⚠️ Guidance Available
{COMPLEX_COUNT}
🔴 Complex Remediation
{UNIQUE_APPS}
Unique Apps
Search:
Violation:
All Violations
Cloud:
All Clouds
Category:
All Categories
Severity:
All
✅ Autofix
⚠️ Guidance
🔴 Complex
App Name ▲▼
Violation ▲▼
Cloud ▲▼
Owner ▲▼
SLA ▲▼
ETA ▲▼
Category ▲▼
TSG
No violations match your current filters.
SFI-TI 3.2.2 Tenant Isolation Violation Report · Generated by GitHub Copilot CLI · {GENERATED}
Step 4 — Save the report
Save the generated HTML file using a timestamped filename:
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
$reportPath = ".\s360-ti322-report-$timestamp.html"
# ... write the HTML content to $reportPath ...
Set-Content -Path $reportPath -Value $htmlContent -Encoding UTF8
Then open in the default browser:
Start-Process $reportPath
Report the full path to the user:
"Report saved to: {reportPath}"
Step 5 — Summary output
After generating the file and opening the browser, print a text summary:
📊 Generated: s360-ti322-report-{timestamp}.html
Total violations: {total}
✅ Autofix eligible: {autofixCount} (SG update scenarios)
⚠️ Guidance available: {guidanceCount} (cert rehoming, FIC setup)
🔴 Complex remediation: {complexCount} (FIC/cross-tenant/connector)
Unique apps: {uniqueApps}
If 3+ violations are in the "red" (complex) category, list the top 3:
🚨 Most complex violations:
1. [{AppDisplayName}] {ViolationTitle} — {ActionOwnerAlias}
2. ...
3. ...
Error handling
| Scenario | Response |
|---|
| No violation data provided | "No violation data. Run fetch-violations first." |
| Empty violations array | "No violations found for this target. Fully compliant 🎉" |
| File write failure | Report the error and suggest an alternate path |
| Unknown ViolationTitle | Classify as yellow severity, category "Unknown", no TSG link |
Classification reference
Full mapping table for quick lookup during generation:
| ViolationTitle | Category | Severity | TSG |
|---|
| AAD Entra Apps in Prod Tenants using certificates in Non-Prod Tenant | Cert Rehoming | yellow | aka.ms/entraQ4 |
| AAD Entra Apps cloud mismatches with Cert Cloud | Cert Rehoming | yellow | aka.ms/entraQ5 |
| AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud auth scenarios | FIC Setup | yellow | aka.ms/entraQ5 |
| AAD Entra Apps cloud mismatches with Cert Cloud - Cross-cloud 1P scenarios | FIC Setup | yellow | aka.ms/entraQ5 |
| 1pApp certs Tenant mismatches the Tenant of the Security Group | SG / Cert Decision | yellow | aka.ms/entraQ6 |
| AAD Entra apps with cross-tenant violations | Cross-Tenant | red | aka.ms/entraQ7 |
| Connector domain OWNER should not use shared subjectName for authentication across tenant | Connector | red | aka.ms/entraQ8 |
| Connector domain CONSUMER should not use shared subjectName for authentication across tenant | Connector | red | aka.ms/entraQ8 |
| 1P App with invalid security group | SG Update | green | aka.ms/entraQ9 |
Key tools used
| Tool | MCP | Purpose |
|---|
PowerShell (Set-Content, Start-Process) | — | Write HTML file, open browser |
fetch-violations skill (upstream) | s360-breeze | Provides violation data input |