Files
rengine/shared/models/instance_settings.py
T
Yogesh OjhaandClaude Opus 5 d506f8be66 feat(bounty-hub): record what changed in a program and alert on it
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
2026-09-07 14:44:18 +05:30

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