Cyvest¶
Build, score, and narrate cybersecurity investigations with a single fluent Python API.
Cyvest turns raw observables into curated stories—complete with scoring, provenance, and export-ready reports.
Start Fast¶
- Install using uv or pip.
- Model your first case via the Quick Start notebook.
- Master the vocabulary with Core Concepts.
Need help choosing the right entry point?
- Automating SOC workflows? Jump straight to Quick Start.
- Running multi-threaded tasks? See Shared Investigation Context.
- Contributing or extending the fluent helpers? Review the Contributing guide.
Platform Highlights¶
| Area | Why it matters | What to look at |
|---|---|---|
| Structured objects | Model observables, checks, TI, tags, and enrichments with typed helpers | cyvest.model, Concepts |
| Deterministic scoring | MAX/SUM propagation, centralized audit log, and automatic level classification | cyvest.score, Scoring System |
| Fluent helpers | Builder-style methods with deterministic keys and safe merges | cyvest.cyvest, Quick Start |
| Shared context | Thread-safe fragments that can reconcile into a single story | cyvest.shared.SharedInvestigationContext, Guide |
| Comparison | Compare investigations with tolerance rules for regression testing | cyvest.compare, Guide |
| Reporting | Export JSON, Markdown, or render rich terminal summaries | cyvest.io_serialization, cyvest.io_rich, Quick Start |
Walkthrough in 60 Seconds¶
from decimal import Decimal
from cyvest import Cyvest
cv = Cyvest(root_data={"type": "email"})
phishing_url = (
cv.observable(cv.OBS.URL, "https://phishing.com", internal=False)
.with_ti("virustotal", Decimal("8.5"), level=cv.LVL.MALICIOUS)
.relate_to(cv.root(), cv.REL.RELATED_TO)
)
(
cv.check("email_url_check", "Analyze embedded URL")
.link_observable(phishing_url)
.with_score(Decimal("8.5"))
)
print(cv.get_global_score(), cv.get_global_level())
Best practice
Store investigation metadata (request ID, analyst, ticket link) in the root observable's extra field by passing root_data to Cyvest(...).
Immutable proxies
The objects returned by cv.observable_*/cv.check_* are read-only *Proxy wrappers. Use the facade or their fluent helper methods to apply changes so scoring stays consistent.
Architecture Snapshot¶
Cyvest (facade + fluent proxies)
└─ Investigation (core state)
├─ Observables & relationships
├─ Checks and tags (workflow context)
├─ Threat intelligence (source, score, taxonomies)
├─ ScoreEngine (MAX/SUM propagation, history)
├─ InvestigationStats (live metrics)
└─ IO / reporting utilities (JSON, Markdown, Rich)
Design principles
- Deterministic keys guarantee lossless merges from concurrent builders.
- Relationship direction controls score propagation.
- The fluent helper layer is thin—everything ultimately stores data inside a single
Investigation.
Typical Journeys¶
| Goal | Recommended Path |
|---|---|
| Evaluate Cyvest in <10 minutes | Getting Started |
| Understand observables vs. checks | Core Concepts |
| Share state across threads | Shared Investigation Context |
| Compare investigations or regression test | Comparing Investigations |
| Extend scoring or fluent helpers | Contributing |
| Embed results in other tools | Quick Start → Exporting Results |
JavaScript Packages¶
@cyvest/cyvest-js: TypeScript types, schema validation, and graph helpers for Cyvest investigations.@cyvest/cyvest-vis: React components (XYFlow + D3) to visualize investigations.@cyvest/cyvest-app: Vite demo bundling the JS packages with sample investigations.
See JavaScript packages guide for install and workspace commands.
Community¶
- github.com/PakitoSec/cyvest
- Report bugs or request features
- Join discussions and share patterns
Cyvest is MIT licensed. Contributions and issue reports are welcome!