Skip to content

Metadata and Extensions

Eric Fitzgerald edited this page Apr 8, 2026 · 2 revisions

Metadata and Extensions

Extend TMI with custom metadata on threat models, diagrams, threats, and other objects.

Overview

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.

What is Metadata?

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

Adding Metadata

Via User Interface

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.

  1. Open the entity (threat model, diagram, threat, etc.)
  2. Click the metadata icon button (a kebab/more menu item on teams and projects, or a direct button on other entities)
  3. In the metadata dialog, click "Add Metadata" to add a new row
  4. Enter the key and value in the inline table fields
  5. 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.

Metadata Constraints

  • 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.

Common Metadata Uses

Categorization

category: web-application
tier: production
environment: cloud

Ownership and Responsibility

owner: security-team
reviewer: john.doe
team: platform-engineering

Compliance and Governance

compliance: PCI-DSS,HIPAA,SOC2
data-classification: confidential
regulatory-requirement: GDPR

Workflow Integration

jira-project: SEC
status: in-review
review-date: 2025-06-01
approval-required: true

Custom Classification

attack-surface: external
data-sensitivity: high
business-criticality: critical

Metadata Best Practices

Consistent Naming

  • 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

Structured Values

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.

Documentation

Document your metadata schema:

  • What keys are used
  • What values are valid
  • What they mean
  • When to use them

API Integration

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.

Endpoint Pattern

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

Reading 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" }
]

Creating Metadata

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.

Updating Metadata

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 Operations

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" }
]

Error Responses

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.

Storage

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.

Advanced Uses

Custom Reporting

Generate reports based on metadata:

  • All high-priority threats
  • Threat models by compliance requirement
  • Items requiring review by date

Integration with External Systems

Map metadata to external systems using well-known keys:

  • jira-project -- Jira project key
  • servicenow-ci -- ServiceNow configuration item
  • repository-url -- GitHub repository URL

Examples

Example 1: Compliance Tracking

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

Example 2: Team Organization

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%

Example 3: Workflow Integration

Threat Metadata:

jira-ticket: SEC-1234
status: in-progress
priority: P1
target-date: 2025-04-01
assigned-to: security-team

Metadata Schema (Recommended)

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, approved

Future Enhancements

Potential future features:

  • Metadata validation and schemas
  • Required metadata fields
  • Metadata templates
  • Metadata inheritance
  • Filtering and searching entities by metadata values

Next Steps

Related Topics

Clone this wiki locally