mirror of
https://github.com/yogeshojha/rengine.git
synced 2026-10-19 14:51:31 +02:00
The first person to see new scope wins, so Bounty Hub now watches for change rather than only listing what is there today. Every sync diffs against what was already stored and writes bounty_events: a program appearing, scope added or removed, an asset flipping in or out of scope, submissions reopening, a VDP starting to pay. An Updates tab reads that feed and the alerting kinds publish through the existing notification layer, so in-app and webhook channels both fire with no new delivery path. The rule that makes it trustworthy is the one used everywhere else: a first observation is not a change. A program read for the first time records a baseline and emits nothing, and a library synced for the first time does not announce 630 new programs. Verified against the live API — a re-sync with nothing changed upstream produces zero events. Sync is scheduled and the interval belongs to the user: off, daily or weekly, chosen in the header. Beat ticks hourly and the task decides whether the interval is due; Refresh from HackerOne passes force and always runs, the same rule the threat-intel feeds follow. Off means nothing leaves the box on a timer, and says so. Also fixes the same paginate() trap twice hit in this feature: a derived field on a …Read model has to carry a default, because paginate coerces the ORM row before the service fills it in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SZEi41ZDRWtwYDPFwoCVnu
91 lines
3.2 KiB
Python
91 lines
3.2 KiB
Python
import uuid
|
|
from datetime import datetime
|
|
|
|
from pydantic import BaseModel
|
|
from sqlalchemy import Column
|
|
from sqlalchemy.types import JSON
|
|
from sqlmodel import Field, SQLModel, UniqueConstraint
|
|
|
|
from shared.definitions.bounty_programs import DEFAULT_SYNC_INTERVAL
|
|
from shared.enums.instance import InstanceMode
|
|
from shared.utils.datetime import utc_now
|
|
|
|
|
|
class InstanceSettings(SQLModel, table=True):
|
|
__tablename__ = "instance_settings"
|
|
__table_args__ = (
|
|
UniqueConstraint("singleton_key", name="uq_instance_settings_singleton"),
|
|
)
|
|
|
|
id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True, index=True)
|
|
singleton_key: str = Field(default="instance", max_length=20)
|
|
instance_name: str = Field(default="reNgine", max_length=120)
|
|
timezone: str = Field(default="UTC", max_length=64)
|
|
mode: str = Field(default=InstanceMode.BUG_BOUNTY.value)
|
|
onboarding_completed: bool = Field(default=False)
|
|
onboarding_completed_at: datetime | None = Field(default=None)
|
|
onboarding_completed_by: uuid.UUID | None = Field(default=None)
|
|
onboarding_step: int = Field(default=0)
|
|
onboarding_state: dict = Field(
|
|
default_factory=dict, sa_column=Column(JSON, nullable=False)
|
|
)
|
|
scan_history_retention_days: int = Field(default=90)
|
|
screenshot_retention_days: int = Field(default=30)
|
|
ai_enabled: bool = Field(default=False)
|
|
ai_provider: str | None = Field(default=None)
|
|
ai_model: str | None = Field(default=None)
|
|
ai_api_key_encrypted: str | None = Field(default=None)
|
|
ai_features: dict = Field(
|
|
default_factory=dict, sa_column=Column(JSON, nullable=False)
|
|
)
|
|
report_defaults: dict = Field(
|
|
default_factory=dict, sa_column=Column(JSON, nullable=False)
|
|
)
|
|
threat_intel_auto_sync: bool = Field(default=True)
|
|
bounty_sync_interval: str = Field(default=DEFAULT_SYNC_INTERVAL, max_length=16)
|
|
bounty_synced_at: datetime | None = Field(default=None)
|
|
bounty_events_seen_at: datetime | None = Field(default=None)
|
|
mcp_enabled: bool = Field(default=False)
|
|
mcp_settings: dict = Field(
|
|
default_factory=dict, sa_column=Column(JSON, nullable=False)
|
|
)
|
|
created_at: datetime = Field(default_factory=utc_now)
|
|
updated_at: datetime = Field(default_factory=utc_now)
|
|
|
|
|
|
class InstanceSettingsUpdate(BaseModel):
|
|
instance_name: str | None = None
|
|
timezone: str | None = None
|
|
mode: str | None = None
|
|
scan_history_retention_days: int | None = None
|
|
screenshot_retention_days: int | None = None
|
|
ai_enabled: bool | None = None
|
|
ai_provider: str | None = None
|
|
ai_model: str | None = None
|
|
ai_api_key: str | None = None
|
|
ai_features: dict | None = None
|
|
|
|
|
|
class InstanceSettingsRead(BaseModel):
|
|
id: uuid.UUID
|
|
singleton_key: str
|
|
instance_name: str
|
|
timezone: str
|
|
mode: str
|
|
onboarding_completed: bool
|
|
onboarding_completed_at: datetime | None
|
|
onboarding_completed_by: uuid.UUID | None
|
|
onboarding_step: int
|
|
onboarding_state: dict
|
|
scan_history_retention_days: int
|
|
screenshot_retention_days: int
|
|
ai_enabled: bool
|
|
ai_provider: str | None
|
|
ai_model: str | None
|
|
ai_api_key_masked: str | None
|
|
ai_configured: bool
|
|
ai_features: dict
|
|
capabilities: list[str]
|
|
created_at: datetime
|
|
updated_at: datetime
|