-
Notifications
You must be signed in to change notification settings - Fork 2
Metadata and Extensions
Extend TMI with custom metadata on threat models, diagrams, threats, and other objects.
TMI supports extensible metadata on all major entity types, allowing you to customize the platform for your workflows and requirements. Metadata is stored as key-value pairs in a dedicated metadata table, keyed by entity type and entity ID.
Metadata consists of custom key-value pairs that you can add to:
- Threat models
- Diagrams
- Threats
- Notes
- Documents
- Repositories
- Assets
- Cells (diagram elements)
- Surveys
- Survey responses
- Teams
- Projects
The UI provides a metadata dialog for managing key-value pairs on supported entities. The dialog is available for threat models, diagrams, threats, notes, documents, repositories, assets, teams, and projects.
- Open the entity (threat model, diagram, threat, etc.)
- Click the metadata icon button (a kebab/more menu item on teams and projects, or a direct button on other entities)
- In the metadata dialog, click "Add Metadata" to add a new row
- Enter the key and value in the inline table fields
- Click "Save" to persist changes
The dialog supports read-only mode for users without edit permissions. Entries with empty keys or values are automatically filtered out on save.
-
Key: 1-256 characters. Allowed characters: alphanumeric, hyphens (
-), underscores (_), dots (.), and colons (:). Must match^[a-zA-Z0-9._\-:]{1,256}$. - Value: String value up to 1024 bytes (UTF-8 encoded). HTML content is sanitized (tags stripped, injection patterns rejected).
- Bulk limit: A maximum of 20 metadata entries per bulk operation.
category: web-application
tier: production
environment: cloud
owner: security-team
reviewer: john.doe
team: platform-engineering
compliance: PCI-DSS,HIPAA,SOC2
data-classification: confidential
regulatory-requirement: GDPR
jira-project: SEC
status: in-review
review-date: 2025-06-01
approval-required: true
attack-surface: external
data-sensitivity: high
business-criticality: critical
- Use kebab-case, snake_case, or dot-separated keys (all are valid)
- Keys may contain only alphanumeric characters, hyphens, underscores, dots, and colons
- Spaces are not allowed in keys
- Be consistent across objects
- Document your schema
For multiple values, use delimiters:
- Comma-separated:
PCI-DSS,HIPAA,SOC2 - Pipe-separated:
team-a|team-b|team-c
Note: Values are plain strings (max 1024 bytes). HTML tags are stripped by the server.
Document your metadata schema:
- What keys are used
- What values are valid
- What they mean
- When to use them
Metadata is managed through dedicated sub-resource endpoints, not embedded in entity PATCH operations. Each entity type that supports metadata exposes the same set of endpoints.
For a given entity, metadata endpoints follow this pattern (example for threat models):
| Method | Path | Description |
|---|---|---|
GET |
/threat_models/{id}/metadata |
List all metadata for an entity |
POST |
/threat_models/{id}/metadata |
Create a single metadata entry |
GET |
/threat_models/{id}/metadata/{key} |
Get a specific metadata entry by key |
PUT |
/threat_models/{id}/metadata/{key} |
Update a specific metadata entry by key |
DELETE |
/threat_models/{id}/metadata/{key} |
Delete a specific metadata entry by key |
POST |
/threat_models/{id}/metadata/bulk |
Bulk create metadata entries (max 20) |
PUT |
/threat_models/{id}/metadata/bulk |
Bulk replace all metadata for an entity |
PATCH |
/threat_models/{id}/metadata/bulk |
Bulk upsert (create or update) metadata entries |
The same pattern applies to all supported entity types:
/threat_models/{threat_model_id}/diagrams/{diagram_id}/metadata/threat_models/{threat_model_id}/threats/{threat_id}/metadata/threat_models/{threat_model_id}/notes/{note_id}/metadata/threat_models/{threat_model_id}/documents/{document_id}/metadata/threat_models/{threat_model_id}/repositories/{repository_id}/metadata/threat_models/{threat_model_id}/assets/{asset_id}/metadata/teams/{team_id}/metadata/projects/{project_id}/metadata/admin/surveys/{survey_id}/metadata/intake/survey_responses/{survey_response_id}/metadata
Metadata is included as an array in entity responses:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Payment System",
"metadata": [
{ "key": "compliance", "value": "PCI-DSS" },
{ "key": "owner", "value": "security-team" },
{ "key": "review-date", "value": "2025-06-01" }
]
}Listing metadata via the sub-resource endpoint returns the same array format:
GET /threat_models/550e8400-e29b-41d4-a716-446655440000/metadata
[
{ "key": "compliance", "value": "PCI-DSS" },
{ "key": "owner", "value": "security-team" }
]Create a single entry:
POST /threat_models/550e8400-e29b-41d4-a716-446655440000/metadata
Content-Type: application/json
{ "key": "status", "value": "reviewed" }
Returns 201 Created. Returns 409 Conflict if the key already exists.
Update an existing entry by key (the request body contains only the value):
PUT /threat_models/550e8400-e29b-41d4-a716-446655440000/metadata/status
Content-Type: application/json
{ "value": "approved" }
Bulk create (all keys must be new):
POST /threat_models/{id}/metadata/bulk
Content-Type: application/json
[
{ "key": "priority", "value": "high" },
{ "key": "reviewer", "value": "john.doe" }
]
Bulk upsert (creates new keys, updates existing):
PATCH /threat_models/{id}/metadata/bulk
Content-Type: application/json
[
{ "key": "priority", "value": "critical" },
{ "key": "new-key", "value": "new-value" }
]
Bulk replace (deletes all existing metadata and replaces with provided set; an empty array clears all metadata):
PUT /threat_models/{id}/metadata/bulk
Content-Type: application/json
[
{ "key": "only-key", "value": "only-value" }
]
Metadata operations return structured error responses:
| Status | Condition |
|---|---|
400 Bad Request |
Invalid key format, value too large, HTML injection detected, or empty request body |
404 Not Found |
Parent entity or metadata key not found |
409 Conflict |
Key already exists (on create) |
500 Internal Server Error |
Database or server failure |
See API-Integration for general API error format details.
Metadata is stored in a dedicated metadata database table with the following columns:
| Column | Type | Description |
|---|---|---|
id |
varchar(36) | Primary key (UUID) |
entity_type |
varchar(50) | Entity type (e.g., threat_model, threat, diagram) |
entity_id |
varchar(36) | UUID of the parent entity |
key |
varchar(256) | Metadata key |
value |
varchar(1024) | Metadata value |
created_at |
timestamp | Creation timestamp |
modified_at |
timestamp | Last modification timestamp |
A unique composite index on (entity_type, entity_id, key) enforces that each key is unique per entity. Additional indexes support lookups by entity, by key, and by key-value combinations.
Generate reports based on metadata:
- All high-priority threats
- Threat models by compliance requirement
- Items requiring review by date
Map metadata to external systems using well-known keys:
-
jira-project-- Jira project key -
servicenow-ci-- ServiceNow configuration item -
repository-url-- GitHub repository URL
Threat Model Metadata:
compliance: PCI-DSS,SOC2
data-classification: highly-confidential
audit-frequency: quarterly
next-review: 2025-Q2
Threat Metadata:
control-id: PCI-6.5.1
compliance-requirement: PCI-DSS
verification-method: code-review
Threat Model Metadata:
team: platform-team
product: payment-service
owner: alice@example.com
technical-lead: bob@example.com
Diagram Metadata:
subsystem: authentication
responsible-team: security-team
sla: 99.99%
Threat Metadata:
jira-ticket: SEC-1234
status: in-progress
priority: P1
target-date: 2025-04-01
assigned-to: security-team
Define a standard schema for your organization:
# TMI Metadata Schema
## Threat Model Level
- `owner`: Team or person responsible
- `compliance`: Applicable compliance frameworks
- `environment`: dev, staging, production
- `data-classification`: public, internal, confidential, restricted
## Threat Level
- `priority`: P0, P1, P2, P3
- `control-id`: Reference to control framework
- `jira-ticket`: Jira ticket ID
- `assigned-to`: Responsible party
## Diagram Level
- `subsystem`: Which subsystem this represents
- `level`: Context, L0, L1, L2
- `review-status`: draft, in-review, approvedPotential future features:
- Metadata validation and schemas
- Required metadata fields
- Metadata templates
- Metadata inheritance
- Filtering and searching entities by metadata values
- Issue-Tracker-Integration -- Link threats to external issue trackers
- API-Integration -- General API integration guide
- Webhook-Integration -- Webhook setup and event handling
- Creating-Your-First-Threat-Model -- Build your first threat model
- Managing-Threats -- Work with threats in TMI
- API-Overview -- TMI API overview
- Using TMI for Threat Modeling
- Accessing TMI
- Authentication
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Timmy AI Assistant
- Metadata and Extensions
- Planning Your Deployment
- Terraform Deployment (AWS, OCI, GCP, Azure)
- Deploying TMI Server
- OCI Container Deployment
- Certificate Automation
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Branding and Customization
- Monitoring and Health
- Cloud Logging
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks
- Getting Started with Development
- Architecture and Design
- API Integration
- Testing
- Contributing
- Extending TMI
- Dependency Upgrade Plans
- DFD Graphing Library Reference
- Migration Instructions