Metadata-Version: 2.4
Name: spot-sdk-python
Version: 2.0.0b12
Summary: SPOT plugin SDK: the plugin contract, the plugin runtime, its clients and test helpers
License: Apache-2.0
Author: SPOT Project
Author-email: spot@sonn.lu
Requires-Python: >=3.11,<3.16
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Requires-Dist: fastapi (>=0.133.0,<1)
Requires-Dist: httpx2 (>=2.13.1,<3)
Requires-Dist: idna (>=3.11,<4)
Requires-Dist: pydantic (>=2.10,<3.0)
Requires-Dist: pydantic-settings (>=2.0.0,<3.0.0)
Requires-Dist: selectolax (>=1.0,<1.1)
Requires-Dist: starlette (>=1.7.0,<2)
Project-URL: Homepage, https://sonn.lu
Description-Content-Type: text/markdown

# spot-sdk-python

The SDK for writing plugins of SPOT, the Spear-Phishing Overwatching
Tool: analyzers, context providers, mail retrievers and responders.

SPOT runs each plugin as a container and calls its `/internal/*` routes
with the plugin's own token. This package holds what SPOT's core and its
plugins share:

- **the contract** (Pydantic models): the email view, verdicts and
  signals, workflow policies, results, and the plugin manifest with its
  OCI labels;
- **the parser** core runs on every message at intake
  (`spot_sdk.mime.parse`), bounded against hostile input, which records
  what mail clients may read differently as anomalies;
- **the plugin runtime**: `create_plugin_app` builds the FastAPI app with
  the routes core calls, token-checked; `PluginSettings` reads the token
  and secrets from `/run/secrets` and the settings from the environment;
- **the clients**: `SpotClient` (ingest, message content, results),
  `KnowledgeClient` (the Knowledge Store) and `LLMClient`
  (OpenAI-compatible chat models, with the email kept apart from the
  instructions as untrusted data);
- **test helpers**: `view_from_eml`, `make_view`, `FakeSpot`,
  `FakeKnowledgeClient`, `FakeLLM` and `assert_contract`.

## Install

```bash
pip install spot-sdk-python==2.0.0b12
```

Python 3.11 to 3.15. Version 2 implements plugin contract 2, for
SPOT 2.0.

## An analyzer

```python
from spot_sdk import (
    AnalyzerVerdict,
    AnalyzeRequest,
    Egress,
    Manifest,
    PluginKind,
    PluginSettings,
    Signal,
    VerdictClass,
    create_plugin_app,
)
from spot_sdk.signals import AUTH_DMARC_FAIL

MANIFEST = Manifest(
    id="analyzer-dmarc",
    version="1.0.0",
    kind=PluginKind.ANALYZER,
    egress=Egress.NONE,
)


def analyze(request: AnalyzeRequest, settings: PluginSettings) -> AnalyzerVerdict:
    failed = [
        result
        for result in request.email.authentication
        if result.method == "dmarc" and result.result == "fail"
    ]
    if not failed:
        return AnalyzerVerdict(verdict=VerdictClass.BENIGN, score=10, confidence=60)
    return AnalyzerVerdict(
        verdict=VerdictClass.SUSPICIOUS,
        score=70,
        confidence=80,
        signals=[Signal(name=AUTH_DMARC_FAIL, weight=60, evidence="dmarc=fail")],
    )


app = create_plugin_app(MANIFEST, PluginSettings, analyze=analyze)
```

Serve it with `uvicorn analyzer_dmarc:app --host 0.0.0.0 --port 8000`,
and test it with `spot_sdk.testing.assert_contract(app, "tests/phish.eml",
token=...)`.

## Documentation

- [Documentation](https://spot-project.codeberg.page/documentation/sdk/):
  the contract, writing each kind of plugin, the reference.
- [Migrating from 1.x](https://spot-project.codeberg.page/documentation/sdk/MIGRATION-2/):
  every removed name and its replacement. SDK 2 has no compatibility
  with contract 1.
- [Source and changelog](https://codeberg.org/SPOT_Project/sdk).

## License

Apache License 2.0.

