Files
trustos/backend/app/schemas/schemas.py
drjones 463dff883b feat: initial TrustOS platform scaffold
- FastAPI backend: auth, findings, dashboard, attack paths, footprint, AI translator, risk calculator, PDF report generator
- Next.js frontend: Vault dashboard, login, findings table, finding detail with AI coach, digital footprint, reports
- PostgreSQL data model: tenants, users, assets, findings, risk scores, audit reports, attack paths
- Docker Compose + Dockerfiles for all services
- Demo seed data: Acme Corp with 6 findings and 90-day risk score history
- AI Risk Translator (OpenAI/Anthropic) with plain-English business impact
- Role-based access: executive / it_admin / trustos_admin
- Scope-lock engine: authorization required before any assessment

Stage 1-8 complete: Phase 1 Vault Audit product ready
2026-07-05 09:46:08 +00:00

203 lines
6.2 KiB
Python

from pydantic import BaseModel, EmailStr, field_validator
from typing import Optional, List
from datetime import datetime
from app.models.models import UserRole, FindingSeverity, FindingStatus, FindingCategory, AssetType
# ─── Auth ────────────────────────────────────────────────────────────────────
class LoginRequest(BaseModel):
email: str
password: str
class TokenResponse(BaseModel):
access_token: str
token_type: str = "bearer"
role: str
tenant_id: str
full_name: str
class UserMe(BaseModel):
id: str
email: str
full_name: str
role: UserRole
tenant_id: str
# ─── Tenant ───────────────────────────────────────────────────────────────────
class TenantBase(BaseModel):
name: str
slug: str
industry: Optional[str] = None
size_range: Optional[str] = None
contact_email: Optional[str] = None
class TenantCreate(TenantBase):
pass
class TenantOut(TenantBase):
id: str
is_active: bool
created_at: datetime
model_config = {"from_attributes": True}
# ─── Finding ──────────────────────────────────────────────────────────────────
class FindingOut(BaseModel):
id: str
tenant_id: str
asset_id: Optional[str] = None
title: str
severity: FindingSeverity
status: FindingStatus
category: FindingCategory
technical_description: Optional[str] = None
cve_id: Optional[str] = None
cvss_score: Optional[float] = None
affected_component: Optional[str] = None
ai_summary: Optional[str] = None
ai_business_impact: Optional[str] = None
ai_impact_level: Optional[str] = None
ai_remediation_steps: Optional[str] = None
ai_fix_priority: Optional[str] = None
assignee_email: Optional[str] = None
due_date: Optional[datetime] = None
is_top_risk: bool
source: Optional[str] = None
created_at: datetime
updated_at: datetime
model_config = {"from_attributes": True}
class FindingCreate(BaseModel):
title: str
severity: FindingSeverity
category: FindingCategory
technical_description: Optional[str] = None
cve_id: Optional[str] = None
cvss_score: Optional[float] = None
affected_component: Optional[str] = None
asset_id: Optional[str] = None
executive_id: Optional[str] = None
source: str = "manual"
class FindingStatusUpdate(BaseModel):
status: FindingStatus
resolution_note: Optional[str] = None
assignee_email: Optional[str] = None
due_date: Optional[datetime] = None
# ─── Risk Score ───────────────────────────────────────────────────────────────
class RiskScoreOut(BaseModel):
id: str
tenant_id: str
score_date: datetime
overall_score: float
score_identity: Optional[float] = None
score_cloud: Optional[float] = None
score_network: Optional[float] = None
score_web: Optional[float] = None
score_credential: Optional[float] = None
score_digital_footprint: Optional[float] = None
score_third_party: Optional[float] = None
critical_count: int
high_count: int
medium_count: int
low_count: int
model_config = {"from_attributes": True}
# ─── Dashboard ────────────────────────────────────────────────────────────────
class RiskCardData(BaseModel):
id: str
title: str
ai_summary: Optional[str]
ai_business_impact: Optional[str]
ai_impact_level: Optional[str]
ai_fix_priority: Optional[str]
severity: str
category: str
class DashboardResponse(BaseModel):
tenant_name: str
current_score: float
previous_score: Optional[float]
score_delta: Optional[float]
score_trend: List[dict] # [{date, score}]
top_risks: List[RiskCardData]
open_critical: int
open_high: int
open_medium: int
total_open: int
baseline_score: Optional[float] = None
baseline_date: Optional[datetime] = None
# ─── Audit Report ─────────────────────────────────────────────────────────────
class AuditReportOut(BaseModel):
id: str
tenant_id: str
title: str
report_date: datetime
baseline_score: Optional[float]
executive_summary: Optional[str]
scope_description: Optional[str]
pdf_path: Optional[str]
is_baseline: bool
generated_by: Optional[str]
created_at: datetime
model_config = {"from_attributes": True}
class AuditReportCreate(BaseModel):
title: str
executive_summary: Optional[str] = None
scope_description: Optional[str] = None
# ─── Attack Path ──────────────────────────────────────────────────────────────
class AttackPathOut(BaseModel):
id: str
finding_id: str
title: str
ai_narrative: Optional[str]
nodes_json: Optional[str]
edges_json: Optional[str]
created_at: datetime
model_config = {"from_attributes": True}
# ─── Authorized Asset ─────────────────────────────────────────────────────────
class AuthorizedAssetCreate(BaseModel):
value: str
asset_type: AssetType
description: Optional[str] = None
authorized_by: str
class AuthorizedAssetOut(BaseModel):
id: str
tenant_id: str
value: str
asset_type: AssetType
description: Optional[str]
authorized_by: Optional[str]
authorized_at: datetime
is_active: bool
model_config = {"from_attributes": True}