185 lines
5.0 KiB
Python
185 lines
5.0 KiB
Python
"""Base types and enums for all ASF domain models."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import enum
|
|
from datetime import datetime, timezone
|
|
from typing import Any, Annotated
|
|
from uuid import UUID, uuid4
|
|
|
|
from pydantic import (
|
|
BaseModel,
|
|
ConfigDict,
|
|
Field,
|
|
field_validator,
|
|
PlainSerializer,
|
|
)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Identifiers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
ASFFieldID = Annotated[
|
|
UUID,
|
|
Field(
|
|
description="ASF unique identifier (UUID v4)",
|
|
examples=["3fa85f64-5717-4562-b3fc-2c963f66afa6"],
|
|
),
|
|
]
|
|
|
|
|
|
def generate_id() -> UUID:
|
|
"""Return a new UUID v4 identifier for an ASF entity."""
|
|
return uuid4()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Datetime helpers — force UTC on the wire
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _utc_serialize(dt: datetime) -> str:
|
|
if dt.tzinfo is None:
|
|
dt = dt.replace(tzinfo=timezone.utc)
|
|
return dt.astimezone(timezone.utc).isoformat().replace("+00:00", "Z")
|
|
|
|
|
|
UTCDatetime = Annotated[
|
|
datetime,
|
|
PlainSerializer(_utc_serialize, return_type=str, when_used="json"),
|
|
]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Base model configuration
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ASFBaseModel(BaseModel):
|
|
"""Base Pydantic model used everywhere in ASF."""
|
|
|
|
model_config = ConfigDict(
|
|
extra="forbid",
|
|
populate_by_name=True,
|
|
use_enum_values=False,
|
|
from_attributes=True,
|
|
str_strip_whitespace=True,
|
|
json_encoders={datetime: _utc_serialize},
|
|
)
|
|
|
|
|
|
class TenantScopedModel(ASFBaseModel):
|
|
"""Any record that belongs to a tenant (Organization)."""
|
|
|
|
tenant_id: ASFFieldID = Field(
|
|
description="Owning tenant (Organization) identifier. "
|
|
"Always validated against the authenticated context — never "
|
|
"trust the value supplied by an untrusted client."
|
|
)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Artifact type universe (extensible, open)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ArtifactType(str, enum.Enum):
|
|
"""Canonical set of Artifact subtypes in the initial bootstrap.
|
|
|
|
This list is intentionally extensible: adding a new kind of lifecycle
|
|
entity is a new ArtifactType value, NOT a new MongoDB collection.
|
|
"""
|
|
|
|
REQUIREMENT = "requirement"
|
|
EPIC = "epic"
|
|
STORY = "story"
|
|
TASK = "task"
|
|
ARCHITECTURE_DECISION = "architecture_decision"
|
|
DOCUMENT = "document"
|
|
SOURCE_FILE = "source_file"
|
|
COMMIT = "commit"
|
|
PULL_REQUEST = "pull_request"
|
|
BUILD = "build"
|
|
TEST = "test"
|
|
SECURITY_FINDING = "security_finding"
|
|
DEPLOYMENT = "deployment"
|
|
RELEASE = "release"
|
|
RUNTIME_EVENT = "runtime_event"
|
|
INCIDENT = "incident"
|
|
AI_ANALYSIS = "ai_analysis"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Relationship types between artifacts
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class RelationshipType(str, enum.Enum):
|
|
"""Canonical relationship predicates between two Artifacts.
|
|
|
|
Semantics: ``source <predicate> target``, e.g.
|
|
``REQ-1 implements TASK-7`` means TASK-7 implements REQ-1.
|
|
For the inverse use IMPLEMENTED_BY.
|
|
"""
|
|
|
|
IMPLEMENTS = "implements"
|
|
IMPLEMENTED_BY = "implemented_by"
|
|
VERIFIES = "verifies"
|
|
VERIFIED_BY = "verified_by"
|
|
GENERATED_FROM = "generated_from"
|
|
DOCUMENTED_BY = "documented_by"
|
|
DEPENDS_ON = "depends_on"
|
|
AFFECTS = "affects"
|
|
DEPLOYED_AS = "deployed_as"
|
|
CAUSED_BY = "caused_by"
|
|
SUPERSEDES = "supersedes"
|
|
RELATED_TO = "related_to"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Job lifecycle
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class JobStatus(str, enum.Enum):
|
|
QUEUED = "queued"
|
|
RUNNING = "running"
|
|
COMPLETED = "completed"
|
|
FAILED = "failed"
|
|
CANCELLED = "cancelled"
|
|
|
|
|
|
class JobPriority(str, enum.Enum):
|
|
LOW = "low"
|
|
NORMAL = "normal"
|
|
HIGH = "high"
|
|
URGENT = "urgent"
|
|
|
|
|
|
class JobType(str, enum.Enum):
|
|
AI_INTERACTIVE = "ai_interactive"
|
|
AI_BACKGROUND = "ai_background"
|
|
INDEXING = "indexing"
|
|
CODE_ANALYSIS = "code_analysis"
|
|
TESTING = "testing"
|
|
DEVOPS = "devops"
|
|
NOTIFICATION = "notification"
|
|
CUSTOM = "custom"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Audit
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AuditAction(str, enum.Enum):
|
|
CREATED = "created"
|
|
UPDATED = "updated"
|
|
DELETED = "deleted"
|
|
ACCESSED = "accessed"
|
|
LOGGED_IN = "logged_in"
|
|
LOGGED_OUT = "logged_out"
|
|
PERMISSION_CHANGED = "permission_changed"
|
|
API_KEY_CREATED = "api_key_created"
|
|
API_KEY_REVOKED = "api_key_revoked"
|