Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ out/
# Runtime artifacts
codeql_dbs/

# raptor-studio test venv (local only — not checked in)
.venv-studio/
packages/studio/__pycache__/
packages/studio/**/__pycache__/
packages/studio/.pytest_cache/
packages/studio/**/.pytest_cache/

# SAGE (opt-in; generated by libexec/raptor-sage-setup)
.mcp.json
.sage/
Expand Down
8 changes: 6 additions & 2 deletions core/project/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@

logger = get_logger()

# Default locations
PROJECTS_DIR = Path.home() / ".raptor" / "projects"
# Default locations. Honors RAPTOR_PROJECTS_DIR env var for test harnesses
# and companion tooling (e.g. raptor-studio) that need to point at a
# non-default registry.
PROJECTS_DIR = Path(
os.environ.get("RAPTOR_PROJECTS_DIR", str(Path.home() / ".raptor" / "projects"))
)
DEFAULT_OUTPUT_BASE = Path("out/projects")


Expand Down
48 changes: 48 additions & 0 deletions core/project/tests/test_env_projects_dir.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""RAPTOR_PROJECTS_DIR env var overrides the default ~/.raptor/projects.

Added so test harnesses and companion tooling (e.g. raptor-studio) can point
raptor at an alternate registry without monkey-patching the module constant.
"""

import importlib
import os
import unittest
from pathlib import Path


class TestEnvProjectsDir(unittest.TestCase):

def _reload_with_env(self, value: str | None):
"""Reload the two modules with RAPTOR_PROJECTS_DIR set (or unset)."""
saved = os.environ.pop("RAPTOR_PROJECTS_DIR", None)
try:
if value is not None:
os.environ["RAPTOR_PROJECTS_DIR"] = value
import core.project.project as p
import core.startup as s
importlib.reload(p)
importlib.reload(s)
return p.PROJECTS_DIR, s.PROJECTS_DIR
finally:
os.environ.pop("RAPTOR_PROJECTS_DIR", None)
if saved is not None:
os.environ["RAPTOR_PROJECTS_DIR"] = saved
# restore module state
import core.project.project as p
import core.startup as s
importlib.reload(p)
importlib.reload(s)

def test_env_var_overrides_default(self):
proj, start = self._reload_with_env("/tmp/raptor-env-test")
self.assertEqual(proj, Path("/tmp/raptor-env-test"))
self.assertEqual(start, Path("/tmp/raptor-env-test"))

def test_default_when_unset(self):
proj, start = self._reload_with_env(None)
self.assertEqual(proj, Path.home() / ".raptor" / "projects")
self.assertEqual(start, Path.home() / ".raptor" / "projects")


if __name__ == "__main__":
unittest.main()
5 changes: 4 additions & 1 deletion core/startup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

# core/startup/__init__.py → core/ → raptor/ (repo root)
REPO_ROOT = Path(__file__).resolve().parents[2]
PROJECTS_DIR = Path.home() / ".raptor" / "projects"
# Honors RAPTOR_PROJECTS_DIR env var; see core/project/project.py for rationale.
PROJECTS_DIR = Path(
os.environ.get("RAPTOR_PROJECTS_DIR", str(Path.home() / ".raptor" / "projects"))
)
ACTIVE_LINK = PROJECTS_DIR / ".active"


Expand Down
90 changes: 90 additions & 0 deletions packages/studio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# raptor studio

A web UI for raptor — browse findings, trigger scans / fuzz / forensics, watch runs live, diff project versions, review exploit PoCs — without leaving the browser.

Reads and writes raptor's project data (`~/.raptor/projects/*.json` + per-run output directories); projects created in the UI are fully interchangeable with `raptor project create`.

**Companion repo**: this package was developed in the open at [yesnet0/raptor-studio](https://github.com/yesnet0/raptor-studio) (27 commits of history). The commit in this PR squashes that history for reviewability; the full timeline lives there.

## Quick start

From the raptor repo root:

```bash
pip install -r requirements.txt # includes studio's extra deps
python3 raptor_studio.py # → http://127.0.0.1:8765
```

If you have no raptor projects yet, the Dashboard shows a Welcome card with a **Create your first project →** button. If you already have projects (from `raptor project create` or a previous studio session), they appear immediately.

**Want a loaded demo?**

```bash
PYTHONPATH=. python3 packages/studio/scripts/seed_demo.py
RAPTOR_PROJECTS_DIR=~/.raptor-studio-demo/projects python3 raptor_studio.py
```

The seed script creates three representative projects (source analysis / binary fuzzing / OSS forensics) with realistic run artifacts.

## Capabilities

| | |
|---|---|
| **Browsing** | Dashboard · Projects · per-project Overview · Findings with full schema (final_status, verdict × impact, Stage E feasibility, chain_breaks, exploitation_paths) · Runs · Diff |
| **Per-run** | Kind-aware summary with scan metrics, fuzzing report, validation bundle counts · inline CodeQL dataflow SVGs · OSS forensics walkthrough (evidence, hypothesis timeline, final report) |
| **Triggering** | Create project (3 types: source / binary / forensics) · SQLite-backed job queue + subprocess worker · live log streaming via SSE · cancel via SIGTERM · Equivalent CLI preview on every form |
| **Runnable kinds** | `scan`, `agentic`, `codeql`, `fuzz` (pure Python) · `understand`, `validate`, `oss-forensics`, `crash-analysis` (shell out to `claude -p`) |
| **Configuration** | Global Settings edits `~/.config/raptor/models.json` (analysis / code / consensus / fallback roles) · Personas browser for the 10 expert briefs · Glossary page for schema terms |

## Environment

| Variable | Default | Purpose |
|---|---|---|
| `RAPTOR_PROJECTS_DIR` | `~/.raptor/projects` | Where raptor stores project registry entries |
| `RAPTOR_OUTPUT_BASE` | `out/projects` | Default base path for new projects' output dirs |
| `STUDIO_DATA_DIR` | `~/.raptor-studio` | Job queue DB, job logs, project-extras sidecars |
| `RAPTOR_MODELS_CONFIG` | `~/.config/raptor/models.json` | Raptor's per-role LLM config |

## Structure

```
packages/studio/
├── app.py # FastAPI entry point (~20 routes)
├── config.py # env-driven runtime paths
├── services/ # 14 modules — readers, writers, job queue, worker, classifiers
├── templates/ # 23 Jinja2 templates (dark + light, Mermaid dataflow, markdown)
├── static/ # velociraptor avatar + (reserved for future css/js)
├── tests/ # 17 test modules (161 tests, incl. live-subprocess worker)
├── scripts/ # seed_demo.py, process_avatar.py
├── docs/
│ ├── PRD.md # product requirements — scope, invariants, non-goals
│ ├── FAQ.md # pre-answers to likely maintainer questions
│ ├── ARCHITECTURE.md # one-page call-flow + request lifecycles + state locations
│ ├── UX_RECONCILIATION.md # design narrative: vulngraph patterns + raptor data model
│ └── CHANGELOG.md # commit-by-commit narrative
└── fixtures/ # test inputs
```

## Tests

```bash
cd <raptor root>
pip install pytest httpx
python -m pytest packages/studio/tests/
```

Expect 160 passed, 1 skipped.

## Design thesis

> Easy for newcomers, not dumbed down, options surfaced without overwhelm.

Raptor's reasoning quality (Semgrep + CodeQL + Stage A–F validation + AFL++ + Z3 + GH Archive forensics) is excellent, but its native surface is a terminal and a Claude-Code slash-command grammar. That's fine for solo deep-dives; it's friction for browsing findings at volume, triaging across runs, diffing before/after, and sharing with non-terminal stakeholders.

The UX borrows idioms from [vulngraph](https://github.com/yesnet0/vulngraph) (project-centric navigation, pipeline-status sidebar, evidence-inline findings, Mermaid graphs) and serves raptor's actual data model (SARIF, Stage A–F validation, verdict × impact, feasibility, chain-breaks, OSS-forensics artifacts, expert personas).

Full rationale: [`docs/PRD.md`](docs/PRD.md) · anticipated maintainer questions: [`docs/FAQ.md`](docs/FAQ.md) · call-flow: [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) · design narrative: [`docs/UX_RECONCILIATION.md`](docs/UX_RECONCILIATION.md).

## License

MIT (matches raptor).
7 changes: 7 additions & 0 deletions packages/studio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"""raptor-studio — web UI for raptor.

Companion to https://github.com/gadievron/raptor. Intended eventual home:
packages/studio/ inside the raptor tree.
"""

__version__ = "0.0.1"
Loading