# stidantic [WIP]

**This is work in progress, compliant but untested.**

A Pydantic-based Python library for parsing, validating, and creating STIX 2.1 cyber threat intelligence data.

[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![Pydantic v2](https://img.shields.io/badge/pydantic-v2.12+-green.svg)](https://docs.pydantic.dev/)
[![STIX v2.1](https://img.shields.io/badge/stix-v2.1+-red.svg)](https://oasis-open.github.io/cti-documentation/stix/intro)

## Overview

**stidantic** provides a type-safe, Pythonic way to work with [STIX 2.1](https://oasis-open.github.io/cti-documentation/stix/intro) (Structured Threat Information Expression) objects.

This library leverages [Pydantic](https://docs.pydantic.dev/) to provide:

- 🔒 **Strong type validation** for all STIX objects
- 📝 **IDE auto-completion** and type hints
- ✅ **Automatic validation** of STIX specification constraints
- 🔄 **Easy JSON serialization/deserialization**
- ❄️ **Immutable models** with frozen Pydantic configurations
- 🎯 **Discriminated unions** for polymorphic STIX object handling

## Installation

### Requirements

- Python 3.12 or later (uses PEP 695 type statements)
- Pydantic >= 2.12

```sh
pip install stidantic
```

## Quick Start

### Parsing a STIX Bundle

```python
from stidantic.bundle import StixBundle

# Load from JSON file
with open("threat_data.json", "r") as f:
    bundle = StixBundle.model_validate_json(f.read())

# Access objects
print(f"Bundle contains {len(bundle.objects)} objects")
for obj in bundle.objects:
    print(f"- {obj.type}: {obj.id}")
```

### Creating STIX Objects

```python
from datetime import datetime
from stidantic.sdo import Campaign
from stidantic.types import Identifier

campaign = Campaign(
    created=datetime.now(),
    modified=datetime.now(),
    name="Operation Stealth",
    description="A sophisticated campaign targeting financial institutions",
    objective="Financial gain through wire fraud"
)

# Export to JSON
json_output = campaign.model_dump_json(indent=2, exclude_none=True, by_alias=True)
print(json_output)
```

### Handling property extensions

```python
from stidantic.marking import MarkingDefinition
from stidantic.extensions.pap import PAPExtensionDefinition, PAPExtension

MarkingDefinition.register_property_extension(PAPExtensionDefinition, PAPExtension)
data = {
    "extensions": {
        "extension-definition--f8d78575-edfd-406e-8e84-6162a8450f5b": {
            "extension_type": "property-extension",
            "pap": "green",
        }
    },
    "created": "2022-10-01T00:00:00Z",
    "name": "PAP:GREEN",
}

pap_green = MarkingDefinition.model_validate(data)
if isinstance(pap_green.extensions[PAPExtensionDefinition.id], PAPExtension):
    print("Extension was parsed & validated by Pydantic.")
```

### Handling new object extensions 

```python
from datetime import datetime
from typing import ClassVar, Literal

from stidantic.bundle import StixBundle
from stidantic.extension import ExtensionDefinition
from stidantic.types import ExtensionType, Identifier, StixObservable

MyNewSCOExtension = ExtensionDefinition(
    id=Identifier(
        "extension-definition--1f260414-30ff-4936-b1e0-0b3a02ebff00",
    ),
    name="my-new-sco",
    version="1.0.0",
    created=datetime.now(),
    modified=datetime.now(),
    created_by_ref=Identifier("identity--a984f569-bd93-4d04-8bfc-c4c56b552503"),
    json_schema="https://github.com/me/myproject/extension-definition--1f260414-30ff-4936-b1e0-0b3a02ebff00.json",
    extension_types=[ExtensionType.new_sco],
)


class MyNewSCO(StixObservable):
    id_contributing_properties: ClassVar[list[str] | None] = ["value"]

    type: Literal["my-new-sco"] = "my-new-sco"
    value: str


StixBundle.register_new_object(definition=MyNewSCOExtension, extension=MyNewSCO)

bundle = {
    "id": "bundle--8d6f7b95-378a-4b0d-8b9c-e253a914b1f7",
    "objects": [
        {
            "type": "my-new-sco",
            "value": "test",
        },
    ],
}

parsed = StixBundle.model_validate(bundle)
if isinstance(parsed.objects[0], MyNewSCO):
    print("Extension was parsed & validated by Pydantic. Deterministic ID was generated.")
```

### Handling top-level property extensions 

Top-level property extensions are supported as `stidantic` objects supports extra properties natively but are **discouraged**. 

Such extensions won't be tracked in `__stix_extensions__` built-in variable attached to stidantic classes. 
This means you won't be able to keep track of such extension definitions and cannot easily export those defintions for sharing purposes.
Extra properties cannot be used for deterministic id generation of STIX cyber-observables.
Note that any top-level property extension attribute will appear in the `__pydantic_extra__` built-in variable.

```python
from stidantic.bundle import StixBundle

bundle = {
    "id": "bundle--f26bbc4b-4233-4e0b-ab5a-276e5cd8109b",
    "objects": [{"type": "ipv4-addr", "value": "198.52.200.4", "usage": "parking"}],
}
parsed = StixBundle.model_validate(bundle)
print(parsed.model_dump_json(indent=2, exclude_none=True))
print(parsed.objects[0].__pydantic_extra__)
```

Beware the STIX standard does not define any name conflict resolution for new STIX Objects or for top-level properties created by the extension mechanism.

## Implemented STIX Objects

### STIX Domain Objects (SDOs)
- ✅ `AttackPattern` - Ways adversaries attempt to compromise targets
- ✅ `Campaign` - Grouping of adversarial behaviors over time
- ✅ `Course of Action` - Action taken to prevent or respond to an attack
- ✅ `Grouping` - Explicitly asserts that STIX Objects have a shared context
- ✅ `Identity` - Actual individuals, organizations, or groups
- ✅ `Incident` - A stub object representing a security incident
- ✅ `Indicator` - Pattern that can be used to detect suspicious or malicious activity
- ✅ `Infrastructure` - Systems, software services, and associated resources
- ✅ `Intrusion Set` - A grouped set of adversarial behaviors and resources
- ✅ `Location` - A geographic location
- ✅ `Malware` - A type of TTP that represents malicious code
- ✅ `Malware Analysis` - The results of a malware analysis
- ✅ `Note` - Analyst-created content and context
- ✅ `Observed Data` - Information about cyber security related entities
- ✅ `Opinion` - An assessment of the correctness of a STIX Object
- ✅ `Report` - Collections of threat intelligence
- ✅ `Threat Actor` - Actual individuals, groups, or organizations
- ✅ `Tool` - Legitimate software that can be used by threat actors
- ✅ `Vulnerability` - A mistake in software that can be used to compromise a system

### STIX Cyber-observable Objects (SCOs)
- ✅ `Artifact` - Binary or file-like objects
- ✅ `AutonomousSystem` - Autonomous System (AS) information
- ✅ `Directory` - A directory on a file system
- ✅ `Domain Name` - A network domain name
- ✅ `Email Address` - An email address
- ✅ `Email Message` - An email message
- ✅ `File` - A computer file
- ✅ `IPv4 Address` - An IPv4 address
- ✅ `IPv6 Address` - An IPv6 address
- ✅ `MAC Address` - A Media Access Control (MAC) address
- ✅ `Mutex` - A mutual exclusion object
- ✅ `Network Traffic` - A network traffic flow
- ✅ `Process` - A running process
- ✅ `Software` - A software product
- ✅ `URL` - A Uniform Resource Locator (URL)
- ✅ `User Account` - A user account on a system
- ✅ `Windows Registry Key` - A key in the Windows registry
- ✅ `X.509 Certificate` - An X.509 certificate

### STIX Relationship Objects (SROs)
- ✅ `Relationship` - Connections between STIX objects
- ✅ `Sighting` - Observations of threat intelligence in the wild

### Meta Objects
- ✅ `MarkingDefinition` - Data markings (includes TLP)
- ✅ `LanguageContent` - Translations and internationalization
- ✅ `ExtensionDefinition` - Custom STIX extensions

### Bundle
- ✅ `StixBundle` - Container for STIX objects

### Extensions
- ✅ `PAP` - Permissible Actions Protocol (PAP) extension from [Oasis](https://github.com/oasis-open/cti-stix-common-objects/blob/main/extension-definition-specifications/pap-marking-definition-f8d/STIX-2.1-PAP-marking-definition.adoc)

## Roadmap

- ~~**Full STIX 2.1 Compliance**~~
- ~~**Python packaging**~~
- **Extensive Testing**
- ~~Mind the datetime datatype serializer to follow the specification (convert to UTC).~~
- ~~Implement auto deterministic UUIv5 generation for STIX Identifiers.~~
- Implement a Indicator to Observable export method (and the other way round ?).
- ~~Add Generics validation for Identifier properties that must be of some type.~~
- ~~STIX Extension Support: Develop a robust and user-friendly mechanism for defining, parsing, and validating custom STIX extensions.~~
- TAXII 2.1 Server: Build a TAXII 2.1 compliant server using FastAPI.
- OCA Standard Extensions: Implement STIX extensions from the [Open Cybersecurity Alliance (OCA)](https://github.com/opencybersecurityalliance/stix-extensions) and [stix-common-objects](https://github.com/oasis-open/cti-stix-common-objects) repositories.
- Performance Tuning: Profile and optimize parsing and serialization.

## Resources

- [STIX 2.1 Specification](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html)
- [STIX 2.1 Introduction](https://oasis-open.github.io/cti-documentation/stix/intro)
- [Pydantic Documentation](https://docs.pydantic.dev/)

## License

stidantic is released under the [MIT License](https://opensource.org/licenses/MIT).

## Acknowledgments

This project implements the STIX 2.1 specification edited by Bret Jordan, Rich Piazza, and Trey Darley, published by the OASIS Cyber Threat Intelligence (CTI) Technical Committee.
