fix(plugins): complete steward rename across bundled plugins; clear lint debt
CI / lint (push) Successful in 3s
CI / unit (push) Successful in 7s
CI / integration (push) Successful in 2m8s

The fabledscryer->steward rename had only ever reached host_agent. The other
five bundled plugins (http, snmp, traefik, unifi, docker) still imported
`from fabledscryer.*` (package no longer exists) and read FABLEDSCRYER_* env
vars — so every one of them was broken at import since the original rebrand.
CI stayed green only because none are enabled by default and migrations don't
import plugin modules. Now that they version in-tree, complete the rename:
- fabledscryer.* -> steward.* imports across all five plugins
- FABLEDSCRYER_* -> STEWARD_* in plugin migration env.py files
- author/repository/homepage + user-facing 'Fabled Scryer' strings -> Steward
- snmp/scheduler.py: also drop dead `now`/datetime; record_metric from steward

Adds tests/test_no_legacy_names.py — fails if 'scryer'/'roundtable' ever
reappear in shipped code (the drift bit twice; this stops a third time).

Also clears pre-existing ruff lint debt (unused imports, semicolon statements,
mid-file import) surfaced by the new lint lane.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 11:22:20 -04:00
parent d925709c77
commit af60ca446d
48 changed files with 142 additions and 124 deletions
+4 -4
View File
@@ -13,8 +13,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
config = context.config
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class DockerContainer(Base):
+3 -3
View File
@@ -1,11 +1,11 @@
name: docker
version: "1.0.0"
description: "Docker container status, resource usage, restart tracking via Docker socket"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
tags:
- containers
- docker
+3 -4
View File
@@ -1,13 +1,12 @@
# plugins/docker/routes.py
from __future__ import annotations
import json
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import DockerContainer, DockerMetric
docker_bp = Blueprint("docker", __name__, template_folder="templates")
+2 -2
View File
@@ -4,8 +4,8 @@ import json
import logging
from datetime import datetime, timezone
from fabledscryer.core.scheduler import ScheduledTask
from fabledscryer.core.alerts import record_metric
from steward.core.scheduler import ScheduledTask
from steward.core.alerts import record_metric
logger = logging.getLogger(__name__)
-1
View File
@@ -106,7 +106,6 @@ async def scrape_docker(socket_path: str, include_stopped: bool) -> list[dict]:
) from exc
results = []
now = datetime.now(timezone.utc)
for container, stats in pairs:
names = container.get("Names") or []
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
+1 -1
View File
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}Docker — Fabled Scryer{% endblock %}
{% block title %}Docker — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
<h1 class="page-title" style="margin-bottom:0;">Docker</h1>
-1
View File
@@ -2,7 +2,6 @@
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
from __future__ import annotations
import asyncio
import json
import logging
import ssl
import time
+4 -4
View File
@@ -13,8 +13,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
config = context.config
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class HttpMonitor(Base):
+3 -3
View File
@@ -1,11 +1,11 @@
name: http
version: "1.0.0"
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
tags:
- monitoring
- http
+3 -4
View File
@@ -1,14 +1,13 @@
# plugins/http/routes.py
from __future__ import annotations
import json
import uuid
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request, redirect, url_for
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import HttpMonitor, HttpResult
http_bp = Blueprint("http", __name__, template_folder="templates")
+3 -3
View File
@@ -3,10 +3,10 @@ from __future__ import annotations
import asyncio
import json
import logging
from datetime import datetime, timezone, timedelta
from datetime import datetime, timezone
from fabledscryer.core.scheduler import ScheduledTask
from fabledscryer.core.alerts import record_metric
from steward.core.scheduler import ScheduledTask
from steward.core.alerts import record_metric
logger = logging.getLogger(__name__)
+1 -1
View File
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block title %}HTTP Monitors — Fabled Scryer{% endblock %}
{% block title %}HTTP Monitors — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
<h1 class="page-title" style="margin-bottom:0;">HTTP Monitors</h1>
+22 -22
View File
@@ -1,6 +1,6 @@
# fabledscryer-plugins / index.yaml
# steward-plugins / index.yaml
#
# Plugin catalog for Fabled Scryer.
# Plugin catalog for Steward.
# Fetched by the app at: Settings → Plugins → Plugin Catalog
#
# After updating an entry, commit and push — changes are live within 5 minutes
@@ -16,12 +16,12 @@ plugins:
- name: http
version: "1.0.0"
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/http-v1.0.0/http.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/http-v1.0.0/http.zip"
checksum_sha256: ""
tags:
- monitoring
@@ -32,12 +32,12 @@ plugins:
- name: docker
version: "1.0.0"
description: "Docker container status, resource usage, and restart tracking via Docker socket"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/docker-v1.0.0/docker.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/docker-v1.0.0/docker.zip"
checksum_sha256: ""
tags:
- containers
@@ -47,12 +47,12 @@ plugins:
- name: traefik
version: "1.0.0"
description: "Traefik reverse proxy metrics and access log integration"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/traefik-v1.0.0/traefik.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/traefik-v1.0.0/traefik.zip"
checksum_sha256: ""
tags:
- proxy
@@ -62,12 +62,12 @@ plugins:
- name: unifi
version: "1.0.0"
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/unifi-v1.0.0/unifi.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/unifi-v1.0.0/unifi.zip"
checksum_sha256: ""
tags:
- network
@@ -77,12 +77,12 @@ plugins:
- name: ups
version: "1.0.0"
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/ups"
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/ups-v1.0.0/ups.zip"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/ups"
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/ups-v1.0.0/ups.zip"
checksum_sha256: ""
tags:
- ups
+3 -3
View File
@@ -2,11 +2,11 @@
name: snmp
version: "1.0.0"
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/snmp"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/snmp"
tags:
- snmp
- network
+2 -2
View File
@@ -3,7 +3,7 @@
Synchronous SNMP GET helper, run via executor.
Requires pysnmp-lextudio (maintained pysnmp fork):
pip install 'fabledscryer[snmp]'
pip install 'steward[snmp]'
If pysnmp is not installed, poll_device() returns an empty dict and logs a warning.
"""
@@ -40,7 +40,7 @@ def poll_device_sync(
"""
if not _pysnmp_available():
logger.warning("pysnmp not installed — SNMP polling disabled. "
"Install with: pip install 'fabledscryer[snmp]'")
"Install with: pip install 'steward[snmp]'")
return {}
from pysnmp.hlapi import (
+3 -3
View File
@@ -5,9 +5,9 @@ from datetime import datetime, timedelta, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.models.metrics import PluginMetric
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.models.metrics import PluginMetric
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
+2 -4
View File
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING:
from quart import Quart
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
logger = logging.getLogger(__name__)
@@ -27,16 +27,14 @@ def make_poll_task(app: "Quart") -> ScheduledTask:
async def _do_poll(app: "Quart") -> None:
from datetime import datetime, timezone
from .poller import poll_device_sync
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", [])
if not devices:
return
loop = asyncio.get_event_loop()
now = datetime.now(timezone.utc)
async with app.db_sessionmaker() as session:
async with session.begin():
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/snmp/templates/snmp/device.html #}
{% extends "base.html" %}
{% block title %}SNMP — {{ device_name }} — Fabled Scryer{% endblock %}
{% block title %}SNMP — {{ device_name }} — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap;">
<a href="/plugins/snmp/" style="color:var(--text-muted);font-size:0.85rem;">&#8592; SNMP</a>
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/snmp/templates/snmp/index.html #}
{% extends "base.html" %}
{% block title %}SNMP — Fabled Scryer{% endblock %}
{% block title %}SNMP — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
+5 -5
View File
@@ -15,11 +15,11 @@ from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config
from alembic import context
# Make fabledscryer importable
# Make steward importable
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401 — core models
from steward.models.base import Base
import steward.models # noqa: F401 — core models
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
config = context.config
@@ -31,14 +31,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
class TraefikMetric(Base):
+3 -3
View File
@@ -2,11 +2,11 @@
name: traefik
version: "1.0.0"
description: "Traefik reverse proxy metrics and access log integration"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
tags:
- proxy
- metrics
+3 -3
View File
@@ -6,9 +6,9 @@ from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
import json
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
+2 -3
View File
@@ -5,7 +5,7 @@ import time
from typing import TYPE_CHECKING
from datetime import datetime
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
if TYPE_CHECKING:
from quart import Quart
@@ -41,7 +41,6 @@ async def _do_scrape(app: "Quart") -> None:
global _prev_metrics, _prev_time
from datetime import datetime, timezone
from sqlalchemy import select
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
from .scraper import (
compute_global_stats,
@@ -49,7 +48,7 @@ async def _do_scrape(app: "Quart") -> None:
extract_certs,
fetch_metrics,
)
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/traefik/templates/traefik/index.html #}
{% extends "base.html" %}
{% block title %}Traefik — Fabled Scryer{% endblock %}
{% block title %}Traefik — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.5rem;">
<div style="display:flex;align-items:baseline;gap:1rem;">
+4 -4
View File
@@ -15,8 +15,8 @@ from alembic import context
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
from fabledscryer.models.base import Base
import fabledscryer.models # noqa: F401
from steward.models.base import Base
import steward.models # noqa: F401
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
config = context.config
@@ -28,14 +28,14 @@ target_metadata = Base.metadata
def _get_url() -> str:
import yaml
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
try:
with open(cfg_path) as f:
cfg = yaml.safe_load(f) or {}
url = cfg.get("database", {}).get("url", "")
except FileNotFoundError:
url = ""
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
return os.environ.get("STEWARD_DATABASE__URL", url)
def run_migrations_offline() -> None:
+1 -1
View File
@@ -4,7 +4,7 @@ import uuid
from datetime import datetime, timezone
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from fabledscryer.models.base import Base
from steward.models.base import Base
# ── Time-series (one row per scrape) ──────────────────────────────────────────
+3 -3
View File
@@ -1,11 +1,11 @@
name: unifi
version: "1.0.0"
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
author: "FabledScryer"
author: "Steward"
license: "MIT"
min_app_version: "0.1.0"
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
tags:
- network
- unifi
+3 -4
View File
@@ -1,13 +1,12 @@
# plugins/unifi/routes.py
from __future__ import annotations
import json
from datetime import datetime, timezone
from quart import Blueprint, current_app, render_template, request
from sqlalchemy import Integer, cast, func, select
from fabledscryer.auth.middleware import require_role
from fabledscryer.models.users import UserRole
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
from steward.auth.middleware import require_role
from steward.models.users import UserRole
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
from .models import (
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
+2 -2
View File
@@ -5,7 +5,7 @@ import logging
from datetime import datetime, timezone
from typing import TYPE_CHECKING
from fabledscryer.core.scheduler import ScheduledTask
from steward.core.scheduler import ScheduledTask
if TYPE_CHECKING:
from quart import Quart
@@ -35,7 +35,7 @@ async def _do_poll(app: "Quart") -> None:
from .client import UnifiClient
from .models import UnifiClientSnapshot, UnifiDevice, UnifiWanStat
from fabledscryer.core.alerts import record_metric
from steward.core.alerts import record_metric
cfg = app.config["PLUGINS"]["unifi"]
+1 -1
View File
@@ -1,6 +1,6 @@
{# plugins/unifi/templates/unifi/index.html #}
{% extends "base.html" %}
{% block title %}UniFi — Fabled Scryer{% endblock %}
{% block title %}UniFi — Steward{% endblock %}
{% block content %}
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.25rem;">
<div style="display:flex;align-items:baseline;gap:1rem;">
+3 -4
View File
@@ -3,13 +3,12 @@ from __future__ import annotations
import asyncio
import uuid
from datetime import datetime, timezone
from pathlib import Path
from quart import (
Blueprint, Response, current_app, redirect, render_template,
request, session, url_for,
Blueprint, Response, current_app, render_template,
request, session,
)
from sqlalchemy import select, update
from sqlalchemy import select
from steward.ansible import executor, sources as src_module
from steward.auth.middleware import require_role
-1
View File
@@ -8,7 +8,6 @@ we trust the HTTPS connection to the discovery-documented token/userinfo endpoin
"""
from __future__ import annotations
import base64
import hashlib
import json
import logging
import os
-1
View File
@@ -1,7 +1,6 @@
# steward/core/plugin_manager.py
from __future__ import annotations
import hashlib
import importlib
import logging
import os
import sys
-2
View File
@@ -6,8 +6,6 @@ Called by the scheduler (hourly check) or triggered manually from Settings.
from __future__ import annotations
import asyncio
import logging
import smtplib
import ssl
from datetime import datetime, timedelta, timezone
from email.message import EmailMessage
+2 -1
View File
@@ -15,7 +15,8 @@ target_metadata = Base.metadata
def get_url() -> str:
import os, yaml
import os
import yaml
def _env(suffix: str) -> str | None:
return os.environ.get(f"STEWARD_{suffix}")
+1 -2
View File
@@ -1,6 +1,5 @@
# steward/settings/routes.py
from __future__ import annotations
import json
import logging
from pathlib import Path
from quart import Blueprint, current_app, render_template, request, redirect, url_for, session
@@ -9,7 +8,7 @@ from steward.auth.middleware import require_role
from steward.core.audit import log_audit
from steward.models.users import UserRole
from steward.core.settings import (
DEFAULTS, get_all_settings, set_setting,
get_all_settings, set_setting,
to_smtp_cfg, to_webhook_cfg, to_ansible_cfg, to_plugins_cfg,
to_oidc_cfg, to_ldap_cfg,
)
+2 -2
View File
@@ -144,12 +144,12 @@
<div class="form-group">
<label>Admin group DN</label>
<input type="text" name="ldap.admin_group_dn" value="{{ settings['ldap.admin_group_dn'] }}"
placeholder="cn=scryer-admins,ou=groups,dc=example,dc=com">
placeholder="cn=steward-admins,ou=groups,dc=example,dc=com">
</div>
<div class="form-group">
<label>Operator group DN</label>
<input type="text" name="ldap.operator_group_dn" value="{{ settings['ldap.operator_group_dn'] }}"
placeholder="cn=scryer-operators,ou=groups,dc=example,dc=com">
placeholder="cn=steward-operators,ou=groups,dc=example,dc=com">
</div>
</div>
+1 -1
View File
@@ -81,7 +81,7 @@
<div style="margin-bottom:2rem;max-width:720px;">
<div class="section-title" style="margin-bottom:0.75rem;">Plugin Repositories</div>
<p style="color:var(--text-muted);font-size:0.84rem;margin-bottom:0.75rem;">
Repositories are remote <code>index.yaml</code> files that Scryer checks for available
Repositories are remote <code>index.yaml</code> files that Steward checks for available
and updated plugins. Add repos from other developers to expand the plugin catalog.
</p>
{% include "settings/_plugin_repos.html" %}
-1
View File
@@ -1,6 +1,5 @@
import pytest
import pytest_asyncio
from pathlib import Path
import textwrap
from steward.app import create_app
@@ -1,3 +1,4 @@
import urllib.error
from unittest.mock import patch
from plugins.host_agent import agent as a
@@ -55,10 +56,6 @@ def test_build_payload_wraps_samples():
assert payload["samples"][0]["cpu_pct"] == 5.0
import urllib.error
from unittest.mock import MagicMock, patch
def test_post_payload_success():
from plugins.host_agent import agent as a
captured = {}
@@ -3,7 +3,9 @@ from plugins.host_agent.agent import RingBuffer
def test_ring_buffer_preserves_order():
rb = RingBuffer(maxlen=3)
rb.push(1); rb.push(2); rb.push(3)
rb.push(1)
rb.push(2)
rb.push(3)
assert list(rb.drain()) == [1, 2, 3]
assert len(rb) == 0
@@ -17,7 +19,8 @@ def test_ring_buffer_drops_oldest_when_full():
def test_ring_buffer_drain_clears_and_is_atomic():
rb = RingBuffer(maxlen=5)
rb.push("a"); rb.push("b")
rb.push("a")
rb.push("b")
out = list(rb.drain())
rb.push("c")
assert out == ["a", "b"]
@@ -2,7 +2,6 @@
import subprocess
from pathlib import Path
import pytest
from jinja2 import Environment, FileSystemLoader
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
-1
View File
@@ -1,4 +1,3 @@
import os
import textwrap
import pytest
from steward.config import load_bootstrap
-1
View File
@@ -1,4 +1,3 @@
import pytest
from steward.models.users import User, UserRole
+35
View File
@@ -0,0 +1,35 @@
"""Regression guard: shipped code must not reference old project names.
The FabledScryer -> Roundtable -> Steward renames repeatedly left stale package
imports behind in the (then separate) plugins (e.g. `from fabledscryer.models...`),
silently breaking every non-host_agent plugin. Now that plugins are folded in-tree
and version with core, this test fails loudly if either legacy name reappears in
the shipped Python / templates / plugin manifests.
"""
from __future__ import annotations
from pathlib import Path
import pytest
_ROOT = Path(__file__).resolve().parent.parent
_TREES = [_ROOT / "steward", _ROOT / "plugins"]
_EXTENSIONS = {".py", ".yaml", ".yml", ".html", ".j2"}
_FORBIDDEN = ("scryer", "roundtable") # case-insensitive; old project names
def _shipped_files():
for tree in _TREES:
for path in tree.rglob("*"):
if path.suffix in _EXTENSIONS and "__pycache__" not in path.parts:
yield path
@pytest.mark.parametrize("name", _FORBIDDEN)
def test_no_legacy_project_name(name):
offenders = [
str(p.relative_to(_ROOT))
for p in _shipped_files()
if name in p.read_text(encoding="utf-8", errors="ignore").lower()
]
assert not offenders, f"legacy name {name!r} found in shipped code: {offenders}"