Files
OPNexus/backend/app/schemas/rule.py
T
Julian Boldt 8128d14da4
Release / verify (push) Canceled after 0s
CI / checks (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 0s
Release / test (push) Canceled after 0s
Release / publish (backend) (push) Canceled after 0s
Release / publish (frontend) (push) Canceled after 0s
Release / publish (proxy) (push) Canceled after 0s
Release / publish (updater) (push) Canceled after 0s
Release v1.28.0
- **Übernehmen: mit vorhandenem zentralem Objekt verknüpfen:** Dieselbe von Hand angelegte Regel, derselbe Alias oder dieselbe NAT-Regel auf mehreren
  Firewalls (z. B. beide HA-Knoten) wird nicht mehr als zweites Objekt übernommen. Im Dialog „Von Firewall übernehmen“ erscheint bei exakter
  Übereinstimmung (nach Einsetzen der Host-Variablen, bei Aliasen inkl. Verweisen) die Aktion **Verknüpfen**: die Firewall wird weiteres Ziel des
  vorhandenen Objekts, die Vorschau zeigt „keine Änderung“, und der nächste Rollout aktualisiert alle Firewalls an einem Objekt. Auf der Firewall wird
  dabei nichts geändert. Unterscheidet sich ein gleichnamiges Objekt, zeigt der Dialog die abweichenden Felder; verknüpft wird dann nie. „Alle
  übernehmbaren“ fragt vorher nach („3 verknüpfen, 2 neu übernehmen, 1 nicht übernehmbar“). Aliase, die bisher wegen „Name existiert“ abgelehnt wurden,
  lassen sich so übernehmen.
  Wartet das vorhandene Objekt gerade auf eine Bestätigung, wird nicht verknüpft; „Alle übernehmbaren“ lässt den Eintrag dann aus. Verknüpfen
  macht ein gerade geöffnetes Bearbeiten-Formular des Objekts ungültig, damit die neue Firewall nicht versehentlich wieder aus den Zielen fällt.

- **Tooltips überarbeitet:** Der deaktivierte Button „Oberfläche öffnen“ nennt jetzt den Grund im Klartext samt nächstem Schritt (statt nur einer
  Variablen wie `GUI_GATEWAY_TOKEN`); dasselbe gilt für ausgeschaltete Funktion, deaktivierte Firewall, Nicht-HTTPS-Adresse und ausgeschaltete
  Zertifikatsprüfung. Texte durchgehend in Du-Form, kürzere VPN-Einleitungen, verständlichere Hinweise bei gesperrten Buttons (Zertifikate, Benutzer,
  Dienste). Icon-Buttons (Bearbeiten, Löschen, Schließen, Reihenfolge) zeigen beim Darüberfahren ihren Namen.
2026-10-21 23:05:16 +02:00

109 lines
3.5 KiB
Python

import uuid
from datetime import datetime
from typing import Literal
from pydantic import BaseModel, ConfigDict, Field, field_validator
from app.schemas.adopt import LinkTarget
class RuleCreate(BaseModel):
description: str = Field(min_length=1, max_length=255)
interface: str = Field(min_length=1, max_length=64)
direction: Literal["in", "out"] = "in"
ipprotocol: Literal["inet", "inet6"] = "inet"
protocol: str = Field(default="any", min_length=1, max_length=16)
action: Literal["pass", "block", "reject"] = "pass"
source_net: str = Field(default="any", min_length=1, max_length=128)
source_port: str | None = Field(default=None, max_length=32)
destination_net: str = Field(default="any", min_length=1, max_length=128)
destination_port: str | None = Field(default=None, max_length=32)
enabled: bool = True
log: bool = False
target_host_ids: list[uuid.UUID] = Field(default_factory=list)
target_group_ids: list[uuid.UUID] = Field(default_factory=list)
@field_validator("description", "interface", "protocol", "source_net", "destination_net")
@classmethod
def nonblank(cls, value):
if not value.strip():
raise ValueError("Feld darf nicht nur Leerzeichen enthalten")
return value.strip()
class DeploymentResult(BaseModel):
model_config = ConfigDict(from_attributes=True)
host_id: uuid.UUID
host_name: str
status: Literal["success", "error", "pending", "reverted", "revert_failed"]
message: str | None = None
# Only set while status == "pending" — the client counts down to this
# and shows the Confirm button until it passes.
revert_deadline: datetime | None = None
class RuleRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
description: str
interface: str
direction: str
ipprotocol: str
protocol: str
action: str
source_net: str
source_port: str | None
destination_net: str
destination_port: str | None
enabled: bool
log: bool = False
created_at: datetime
updated_at: datetime
target_host_ids: list[uuid.UUID]
target_group_ids: list[uuid.UUID] = Field(default_factory=list)
effective_host_ids: list[uuid.UUID] = Field(default_factory=list)
workflow_state: Literal["attention", "pending", "cleanup", "unassigned", "disabled", "draft", "synced"]
workflow_counts: dict[str, int]
deployments: list[DeploymentResult]
class RuleEdit(RuleCreate):
expected_updated_at: datetime
class DeployApproval(BaseModel):
preview_token: str = Field(min_length=64, max_length=64)
class AdoptRequest(BaseModel):
host_id: uuid.UUID
# Link to this existing central rule instead of creating a new one (services/adopt_link_service.py).
link_to: uuid.UUID | None = None
rule_uuid: str = Field(min_length=1, max_length=64)
class UnmanagedRule(BaseModel):
uuid: str
description: str
interface: str
interface_label: str
direction: str
action: str
protocol: str
source_net: str
source_port: str
destination_net: str
destination_port: str
enabled: bool
log: bool
adoptable: bool
# Codes such as "negated_source" or "not_quick"; the UI turns them into text.
reasons: list[str]
# Central rules equal to this one (resolved for the host), same-description rules that differ, link possible.
matches: list[LinkTarget] = Field(default_factory=list)
similar: list[LinkTarget] = Field(default_factory=list)
linkable: bool = False