Files
awesome-copilot/skills/threat-model-analyst/references/diagram-conventions.md
Vijay Chegu afba5b86b8 Add threat-model-analyst skill: STRIDE-A threat modeling for repositories (#1177)
* Add threat-model-analyst skill: STRIDE-A threat modeling for repositories

Add a comprehensive threat model analysis skill that performs security audits
using STRIDE-A (STRIDE + Abuse) threat modeling, Zero Trust principles, and
defense-in-depth analysis.

Supports two modes:
- Single analysis: full STRIDE-A threat model producing architecture overviews,
  DFD diagrams, prioritized findings, and executive assessments
- Incremental analysis: security posture diff between baseline report and current
  code, producing standalone reports with embedded comparison

Includes bundled reference assets:
- Orchestrator workflows (full and incremental)
- Analysis principles and verification checklists
- Output format specifications and skeleton templates
- DFD diagram conventions and TMT element taxonomy

* Address PR review comments from Copilot reviewer

- Fix SKILL.md description: use single-quoted scalar, rename mode (2) to
  'Incremental analysis' with accurate description
- Replace 'Compare Mode (Deprecated)' sections with 'Comparing Commits or
  Reports' redirect (no deprecated language for first release)
- Fix skeleton-findings.md: move Tier 1 table rows under header, add
  CONDITIONAL-EMPTY block after END-REPEAT (matching Tier 2/3 structure)
- Fix skeleton-threatmodel.md and skeleton-architecture.md: use 4-backtick
  outer fences to avoid nested fence conflicts with inner mermaid fences
- Fix skeleton-incremental-html.md: correct section count from 9 to 8
- Fix output-formats.md: change status 'open' to 'Open' in JSON example,
  move stride_category warning outside JSON fence as blockquote
- Fix incremental-orchestrator.md: replace stale compare-output-formats.md
  reference with inline color conventions
- Regenerate docs/README.skills.md with updated description

* Address second round of Copilot review comments

- Fix diagram-conventions.md: bidirectional flow notation now uses <-->
  matching orchestrator.md and DFD templates
- Fix tmt-element-taxonomy.md: normalize SE.DF.SSH/LDAP/LDAPS to use
  SE.DF.TMCore.* prefix consistent with all other data flow IDs
- Fix output-formats.md: correct TMT category example from SQLDatabase
  to SQL matching taxonomy, fix component type from 'datastore' to
  'data_store' matching canonical enum, remove DaprSidecar from
  inbound_from per no-standalone-sidecar rule
- Fix 5 skeleton files: clarify VERBATIM instruction to 'copy the
  template content below (excluding the outer code fence)' to prevent
  agents from wrapping output in markdown fences
- Genericize product-specific names in examples: replace edgerag with
  myapp, BitNetManager with TaskProcessor, AzureLocalMCP with MyApp.Core,
  AzureLocalInfra with OnPremInfra, MilvusVectorDB with VectorDB

* Address third round of Copilot review comments

- Fix diagram-conventions.md: second bidirectional two-arrow pattern in
  Quick Reference section now uses <-->
- Fix incremental-orchestrator.md: renumber HTML sections 5-9 to 4-8
  matching skeleton-incremental-html.md 8-section structure
- Fix output-formats.md: add incremental-comparison.html to File List
  as conditional output for incremental mode
- Fix skeleton-inventory.md: add tmt_type, sidecars, and boundary_kind
  fields to match output-formats.md JSON schema example
2026-03-30 07:58:56 +11:00

492 lines
18 KiB
Markdown

# Diagram Conventions — Mermaid Diagrams for Threat Models & Architecture
This file contains ALL rules for creating Mermaid diagrams in threat model reports. It is self-contained — everything needed to produce correct diagrams is here.
---
## ⛔ CRITICAL RULES — READ BEFORE DRAWING ANY DIAGRAM
These rules are the most frequently violated. Read them first, and re-check after every diagram.
### Rule 1: Kubernetes Sidecar Co-location (MANDATORY)
When the target system runs on Kubernetes, **containers that share a Pod must be represented together** — never as independent standalone components.
**DO THIS — annotate the primary container's label:**
```
InferencingFlow(("Inferencing Flow<br/>+ MISE, Dapr")):::process
IngestionFlow(("Ingestion Flow<br/>+ MISE, Dapr")):::process
VectorDbApi(("VectorDB API<br/>+ Dapr")):::process
```
**DO NOT DO THIS — never create standalone sidecar nodes:**
```
❌ MISE(("MISE Sidecar")):::process
❌ DaprSidecar(("Dapr Sidecar")):::process
❌ InferencingFlow -->|"localhost"| MISE
```
**Why:** Sidecars (Dapr, MISE/auth proxy, Envoy, Istio proxy, log collectors) share the Pod's network namespace, lifecycle, and security context with their primary container. They are NOT independent services.
**This rule applies to ALL diagram types:** architecture, threat model, summary.
### Rule 2: No Intra-Pod Flows (MANDATORY)
**DO NOT draw data flows between a primary container and its sidecars.** These are implicit from the co-location annotation.
```
❌ InferencingFlow -->|"localhost:3500"| DaprSidecar
❌ InferencingFlow -->|"localhost:8080"| MISE
```
Intra-pod communication happens on localhost — it has no security boundary and should not appear in the diagram.
### Rule 3: Cross-Boundary Sidecar Flows Originate from Host Container
When a sidecar makes a call that crosses a trust boundary (e.g., MISE → Azure AD, Dapr → Redis), draw the arrow **from the host container node** — never from a standalone sidecar node.
```
✅ InferencingFlow -->|"HTTPS (MISE auth)"| AzureAD
✅ IngestionAPI -->|"HTTPS (MISE auth)"| AzureAD
✅ InferencingFlow -->|"TCP (Dapr)"| Redis
❌ MISESidecar -->|"HTTPS"| AzureAD
❌ DaprSidecar -->|"TCP"| Redis
```
If multiple pods have the same sidecar calling the same external target, draw one arrow per host container. Multiple arrows to the same target is correct.
### Rule 4: Element Table — No Separate Sidecar Rows
Do NOT add separate Element Table rows for sidecars. Describe them in the host container's description column:
```
✅ | Inferencing Flow | Process | API service + MISE auth proxy + Dapr sidecar | Backend Services |
❌ | MISE Sidecar | Process | Auth proxy for Inferencing Flow | Backend Services |
```
If a sidecar class has its own threat surface (e.g., MISE auth bypass), it gets a `## Component` section in STRIDE analysis — but it is still NOT a separate diagram node.
---
## Pre-Render Checklist (VERIFY BEFORE FINALIZING)
After drawing ANY diagram, verify:
- [ ] **Every K8s service node annotated with sidecars?** — Each pod's process node includes `<br/>+ SidecarName` for all co-located containers
- [ ] **Zero standalone sidecar nodes?** — Search diagram for any node named `MISE`, `Dapr`, `Envoy`, `Istio`, `Sidecar` — these must NOT exist as separate nodes
- [ ] **Zero intra-pod localhost flows?** — No arrows between a container and its sidecars on localhost
- [ ] **Cross-boundary sidecar flows from host?** — All arrows to external targets (Azure AD, Redis, etc.) originate from the host container node
- [ ] **Background forced to white?**`%%{init}%%` block includes `'background': '#ffffff'`
- [ ] **All classDef include `color:#000000`?** — Black text on every element
- [ ] **`linkStyle default` present?** — `stroke:#666666,stroke-width:2px`
- [ ] **All labels quoted?**`["Name"]`, `(("Name"))`, `-->|"Label"|`
- [ ] **Subgraph/end pairs matched?** — Every `subgraph` has a closing `end`
- [ ] **Trust boundary styles applied?**`stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5`
---
## Color Palette
> **⛔ CRITICAL: Use ONLY these exact hex codes. Do NOT invent colors, use Chakra UI colors (#4299E1, #48BB78, #E53E3E), Tailwind colors, or any other palette. The colors below are from ColorBrewer qualitative palettes for colorblind accessibility. COPY the classDef lines VERBATIM from this file.**
These colors are shared across ALL Mermaid diagrams. Colors are from ColorBrewer qualitative palettes — designed for colorblind accessibility.
| Color Role | Fill | Stroke | Used For |
|------------|------|--------|----------|
| Blue | `#6baed6` | `#2171b5` | Services/Processes |
| Amber | `#fdae61` | `#d94701` | External Interactors |
| Green | `#74c476` | `#238b45` | Data Stores |
| Red | n/a | `#e31a1c` | Trust boundaries (threat model only) |
| Dark gray | n/a | `#666666` | Arrows/links |
| Text | all: `color:#000000` | | Black text on every element |
### Design Rationale
| Element | Fill | Stroke | Text | Why |
|---------|------|--------|------|-----|
| Process | `#6baed6` | `#2171b5` | `#000000` | Medium blue — visible on both themes |
| External Interactor | `#fdae61` | `#d94701` | `#000000` | Warm amber — distinct from blue/green |
| Data Store | `#74c476` | `#238b45` | `#000000` | Medium green — natural for storage |
| Trust Boundary | none | `#e31a1c` | n/a | Red dashed — 3px for visibility |
| Arrows/Links | n/a | `#666666` | n/a | Dark gray on white background |
| Background | `#ffffff` | n/a | n/a | Forced white for dark theme safety |
---
## Forced White Background (REQUIRED)
Every Mermaid diagram — flowchart and sequence — MUST include an `%%{init}%%` block that forces a white background. This ensures diagrams render correctly in dark themes.
> **⛔ CRITICAL: Do NOT add `primaryColor`, `secondaryColor`, `tertiaryColor`, or ANY custom color keys to themeVariables. The init block controls ONLY the background and line color. ALL element colors come from classDef lines — never from themeVariables. If you add color overrides to themeVariables, they will BREAK the classDef palette.**
### Flowchart Init Block
Add as the **first line** of every `.mmd` file or ` ```mermaid ` flowchart:
```
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
```
**THE ABOVE IS THE ONLY ALLOWED INIT BLOCK FOR FLOWCHARTS.** Do not modify it. Do not add keys. Copy it verbatim.
### Arrow / Link Default Styling
Add after classDef lines:
```
linkStyle default stroke:#666666,stroke-width:2px
```
### Sequence Diagram Init Block
Sequence diagrams cannot use `classDef`. Use this init block:
```
%%{init: {'theme': 'base', 'themeVariables': {
'background': '#ffffff',
'actorBkg': '#6baed6', 'actorBorder': '#2171b5', 'actorTextColor': '#000000',
'signalColor': '#666666', 'signalTextColor': '#666666',
'noteBkgColor': '#fdae61', 'noteBorderColor': '#d94701', 'noteTextColor': '#000000',
'activationBkgColor': '#ddeeff', 'activationBorderColor': '#2171b5',
'sequenceNumberColor': '#767676',
'labelBoxBkgColor': '#f0f0f0', 'labelBoxBorderColor': '#666666', 'labelTextColor': '#000000',
'loopTextColor': '#000000'
}}}%%
```
---
## Diagram Type: Threat Model (DFD)
Used in: `1-threatmodel.md`, `1.1-threatmodel.mmd`, `1.2-threatmodel-summary.mmd`
### `.mmd` File Format — CRITICAL
The `.mmd` file contains **raw Mermaid source only** — no markdown, no code fences. The file must start on line 1 with:
```
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
```
Followed by `flowchart LR` on line 2. NEVER use `flowchart TB`.
**WRONG**: File starts with ` ```plaintext ` or ` ```mermaid ` — these are code fences and corrupt the `.mmd` file.
### ClassDef & Shapes
```
classDef process fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
```
| Element Type | Shape Syntax | Example |
|-------------|-------------|---------|
| Process | `(("Name"))` circle | `WebApi(("Web API")):::process` |
| External Interactor | `["Name"]` rectangle | `User["User/Browser"]:::external` |
| Data Store | `[("Name")]` cylinder | `Database[("PostgreSQL")]:::datastore` |
### Trust Boundary Styling
```
subgraph BoundaryId["Display Name"]
%% elements inside
end
style BoundaryId fill:none,stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5
```
### Flow Labels
```
Unidirectional: A -->|"Label"| B
Bidirectional: A <-->|"Label"| B
```
### Data Flow IDs
- Detailed flows: `DF01`, `DF02`, `DF03`...
- Summary flows: `SDF01`, `SDF02`, `SDF03`...
### Complete DFD Template
```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
flowchart LR
classDef process fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
linkStyle default stroke:#666666,stroke-width:2px
User["User/Browser"]:::external
subgraph Internal["Internal Network"]
WebApi(("Web API")):::process
Database[("PostgreSQL")]:::datastore
end
User <-->|"HTTPS"| WebApi
WebApi <-->|"SQL/TLS"| Database
style Internal fill:none,stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5
```
### Kubernetes DFD Template (With Sidecars)
```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
flowchart LR
classDef process fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
linkStyle default stroke:#666666,stroke-width:2px
User["User/Browser"]:::external
IdP["Identity Provider"]:::external
subgraph K8s["Kubernetes Cluster"]
subgraph Backend["Backend Services"]
ApiService(("API Service<br/>+ AuthProxy, Dapr")):::process
Worker(("Worker<br/>+ Dapr")):::process
end
Redis[("Redis")]:::datastore
Database[("PostgreSQL")]:::datastore
end
User -->|"HTTPS"| ApiService
ApiService -->|"HTTPS"| User
ApiService -->|"HTTPS"| IdP
ApiService -->|"SQL/TLS"| Database
ApiService -->|"Dapr HTTP"| Worker
ApiService -->|"TCP"| Redis
Worker -->|"SQL/TLS"| Database
style K8s fill:none,stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5
style Backend fill:none,stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5
```
**Key points:**
- AuthProxy and Dapr are annotated on the host node (`+ AuthProxy, Dapr`), not as separate nodes
- `ApiService -->|"HTTPS"| IdP` = auth proxy's cross-boundary call, drawn from host container
- `ApiService -->|"TCP"| Redis` = Dapr's cross-boundary call, drawn from host container
- No intra-pod flows drawn
---
## Diagram Type: Architecture
Used in: `0.1-architecture.md` only
### ClassDef & Shapes
```
classDef service fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
```
| Element Type | Shape Syntax | Notes |
|-------------|-------------|-------|
| Services/Processes | `["Name"]` or `(["Name"])` | Rounded rectangles or stadium |
| External Actors | `(["Name"])` with `external` class | Amber distinguishes them |
| Data Stores | `[("Name")]` cylinder | Same as DFD |
| **DO NOT** use circles `(("Name"))` | | Reserved for DFD threat model diagrams |
### Layer Grouping Styling (NOT trust boundaries)
```
style LayerId fill:#f0f4ff,stroke:#2171b5,stroke-width:2px,stroke-dasharray: 5 5
```
Layer colors:
- Backend: `fill:#f0f4ff,stroke:#2171b5` (light blue)
- Data: `fill:#f0fff0,stroke:#238b45` (light green)
- External: `fill:#fff8f0,stroke:#d94701` (light amber)
- Infrastructure: `fill:#f5f5f5,stroke:#666666` (light gray)
### Flow Conventions
- Label with **what is communicated**: `"User queries"`, `"Auth tokens"`, `"Log data"`
- Protocol can be parenthetical: `"Queries (gRPC)"`
- Simpler arrows than DFD — use `-->` without requiring bidirectional flows
### Kubernetes Pods in Architecture Diagrams
Show pods with their full container composition:
```
inf["Inferencing Flow<br/>+ MISE + Dapr"]:::service
ing["Ingestion Flow<br/>+ MISE + Dapr"]:::service
```
### Key Difference from DFD
The architecture diagram shows **what the system does** (logical components and interactions). The threat model DFD shows **what could be attacked** (trust boundaries, data flows with protocols, element types). They share many components but serve different purposes.
### Complete Architecture Diagram Template
```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
flowchart LR
classDef service fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
linkStyle default stroke:#666666,stroke-width:2px
User(["User"]):::external
subgraph Backend["Backend Services"]
Api["API Service"]:::service
Worker["Worker"]:::service
end
subgraph Data["Data Layer"]
Db[("Database")]:::datastore
Cache[("Cache")]:::datastore
end
User -->|"HTTPS"| Api
Api --> Worker
Worker --> Db
Api --> Cache
style Backend fill:#f0f4ff,stroke:#2171b5,stroke-width:2px,stroke-dasharray: 5 5
style Data fill:#f0fff0,stroke:#238b45,stroke-width:2px,stroke-dasharray: 5 5
```
### Kubernetes Architecture Template
```mermaid
%%{init: {'theme': 'base', 'themeVariables': { 'background': '#ffffff', 'primaryColor': '#ffffff', 'lineColor': '#666666' }}}%%
flowchart LR
classDef service fill:#6baed6,stroke:#2171b5,stroke-width:2px,color:#000000
classDef external fill:#fdae61,stroke:#d94701,stroke-width:2px,color:#000000
classDef datastore fill:#74c476,stroke:#238b45,stroke-width:2px,color:#000000
linkStyle default stroke:#666666,stroke-width:2px
User(["User"]):::external
IdP(["Azure AD"]):::external
subgraph K8s["Kubernetes Cluster"]
Inf["Inferencing Flow<br/>+ MISE + Dapr"]:::service
Ing["Ingestion Flow<br/>+ MISE + Dapr"]:::service
Redis[("Redis")]:::datastore
end
User -->|"HTTPS"| Inf
Inf -->|"Auth (MISE)"| IdP
Ing -->|"Auth (MISE)"| IdP
Inf -->|"State (Dapr)"| Redis
style K8s fill:#f0f4ff,stroke:#2171b5,stroke-width:2px,stroke-dasharray: 5 5
```
---
## Sequence Diagram Rules
Used in: `0.1-architecture.md` top scenarios
- The **first 3 scenarios MUST** each include a Mermaid `sequenceDiagram`
- Scenarios 4-5 may optionally include one
- Use the **Sequence Diagram Init Block** above at the top of each
- Use `participant` aliases matching the Key Components table
- Show activations (`activate`/`deactivate`) for request-response patterns
- Include `Note` blocks for security-relevant steps (e.g., "Validates JWT token")
- Keep diagrams focused — core workflow, not every error path
### Complete Sequence Diagram Example
```mermaid
%%{init: {'theme': 'base', 'themeVariables': {
'background': '#ffffff',
'actorBkg': '#6baed6', 'actorBorder': '#2171b5', 'actorTextColor': '#000000',
'signalColor': '#666666', 'signalTextColor': '#666666',
'noteBkgColor': '#fdae61', 'noteBorderColor': '#d94701', 'noteTextColor': '#000000',
'activationBkgColor': '#ddeeff', 'activationBorderColor': '#2171b5'
}}}%%
sequenceDiagram
actor User
participant Api as API Service
participant Db as Database
User->>Api: POST /resource
activate Api
Note over Api: Validates JWT token
Api->>Db: INSERT query
Db-->>Api: Result
Api-->>User: 201 Created
deactivate Api
```
---
## Summary Diagram Rules
Used in: `1.2-threatmodel-summary.mmd` (generated only when detailed diagram has >15 elements or >4 trust boundaries)
1. **All trust boundaries must be preserved** — never combine or omit
2. **Only combine components that are NOT**: entry points, core flow components, security-critical services, primary data stores
3. **Candidates for aggregation**: supporting infrastructure, secondary caches, multiple externals at same trust level
4. **Combined element labels must list contents:**
```
DataLayer[("Data Layer<br/>(UserDB, OrderDB, Redis)")]
SupportServices(("Supporting<br/>(Logging, Monitoring)"))
```
5. Use `SDF` prefix for summary data flows: `SDF01`, `SDF02`, ...
6. Include mapping table in `1-threatmodel.md`:
```
| Summary Element | Contains | Summary Flows | Maps to Detailed Flows |
```
---
## Naming Conventions
| Item | Convention | Example |
|------|-----------|---------|
| Element ID | PascalCase, no spaces | `WebApi`, `UserDb` |
| Display Name | Human readable in quotes | `"Web API"`, `"User Database"` |
| Flow Label | Protocol or action in quotes | `"HTTPS"`, `"SQL"`, `"gRPC"` |
| Flow ID | Unique short identifier | `DF01`, `DF02` |
| Boundary ID | PascalCase | `InternalNetwork`, `PublicDMZ` |
**CRITICAL: Always quote ALL text in Mermaid diagrams:**
- Element labels: `["Name"]`, `(("Name"))`, `[("Name")]`
- Flow labels: `-->|"Label"|`
- Subgraph titles: `subgraph ID["Title"]`
---
## Quick Reference - Shapes
```
External Interactor: ["Name"] → Rectangle
Process: (("Name")) → Circle (double parentheses)
Data Store: [("Name")] → Cylinder
```
## Quick Reference - Flows
```
Unidirectional: A -->|"Label"| B
Bidirectional: A <-->|"Label"| B
```
## Quick Reference - Boundaries
```
subgraph BoundaryId["Display Name"]
%% elements inside
end
style BoundaryId fill:none,stroke:#e31a1c,stroke-width:3px,stroke-dasharray: 5 5
```
---
## STRIDE Analysis — Sidecar Implications
Although sidecars are NOT separate diagram nodes, they DO appear in STRIDE analysis:
- Sidecars with distinct threat surfaces (e.g., MISE auth bypass, Dapr mTLS) get their own `## Component` section in `2-stride-analysis.md`
- The component heading notes which pods they are co-located in
- Threats related to intra-pod communication (localhost bypass, shared namespace) go under the **primary container's** component section
- **Pod Co-location** line in STRIDE template: list co-located sidecars (e.g., "MISE Sidecar, Dapr Sidecar")