fix(plugins): complete steward rename across bundled plugins; clear lint debt
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:
@@ -13,8 +13,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
|
from plugins.docker.models import DockerContainer, DockerMetric # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import DateTime, Float, Integer, String, Text
|
from sqlalchemy import DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class DockerContainer(Base):
|
class DockerContainer(Base):
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: docker
|
name: docker
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Docker container status, resource usage, restart tracking via Docker socket"
|
description: "Docker container status, resource usage, restart tracking via Docker socket"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
|
||||||
tags:
|
tags:
|
||||||
- containers
|
- containers
|
||||||
- docker
|
- docker
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# plugins/docker/routes.py
|
# plugins/docker/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
|
||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import DockerContainer, DockerMetric
|
from .models import DockerContainer, DockerMetric
|
||||||
|
|
||||||
docker_bp = Blueprint("docker", __name__, template_folder="templates")
|
docker_bp = Blueprint("docker", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ async def scrape_docker(socket_path: str, include_stopped: bool) -> list[dict]:
|
|||||||
) from exc
|
) from exc
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
for container, stats in pairs:
|
for container, stats in pairs:
|
||||||
names = container.get("Names") or []
|
names = container.get("Names") or []
|
||||||
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
|
name = names[0].lstrip("/") if names else _short_id(container.get("Id", ""))
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Docker — Fabled Scryer{% endblock %}
|
{% block title %}Docker — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
<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>
|
<h1 class="page-title" style="margin-bottom:0;">Docker</h1>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
|
"""Core HTTP check logic — runs a single monitor check and returns a result dict."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import ssl
|
import ssl
|
||||||
import time
|
import time
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
|
from plugins.http.models import HttpMonitor, HttpResult # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -26,14 +26,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class HttpMonitor(Base):
|
class HttpMonitor(Base):
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: http
|
name: http
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
|
||||||
tags:
|
tags:
|
||||||
- monitoring
|
- monitoring
|
||||||
- http
|
- http
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
# plugins/http/routes.py
|
# plugins/http/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from quart import Blueprint, current_app, render_template, request, redirect, url_for
|
from quart import Blueprint, current_app, render_template, request, redirect, url_for
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import HttpMonitor, HttpResult
|
from .models import HttpMonitor, HttpResult
|
||||||
|
|
||||||
http_bp = Blueprint("http", __name__, template_folder="templates")
|
http_bp = Blueprint("http", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
from fabledscryer.core.alerts import record_metric
|
from steward.core.alerts import record_metric
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}HTTP Monitors — Fabled Scryer{% endblock %}
|
{% block title %}HTTP Monitors — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem;flex-wrap:wrap;">
|
<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>
|
<h1 class="page-title" style="margin-bottom:0;">HTTP Monitors</h1>
|
||||||
|
|||||||
+22
-22
@@ -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
|
# Fetched by the app at: Settings → Plugins → Plugin Catalog
|
||||||
#
|
#
|
||||||
# After updating an entry, commit and push — changes are live within 5 minutes
|
# After updating an entry, commit and push — changes are live within 5 minutes
|
||||||
@@ -16,12 +16,12 @@ plugins:
|
|||||||
- name: http
|
- name: http
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
description: "Synthetic HTTP endpoint monitoring — status code, response time, content match, TLS expiry"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/http"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/http"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/http-v1.0.0/http.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/http-v1.0.0/http.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- monitoring
|
- monitoring
|
||||||
@@ -32,12 +32,12 @@ plugins:
|
|||||||
- name: docker
|
- name: docker
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Docker container status, resource usage, and restart tracking via Docker socket"
|
description: "Docker container status, resource usage, and restart tracking via Docker socket"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/docker"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/docker"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/docker-v1.0.0/docker.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/docker-v1.0.0/docker.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- containers
|
- containers
|
||||||
@@ -47,12 +47,12 @@ plugins:
|
|||||||
- name: traefik
|
- name: traefik
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Traefik reverse proxy metrics and access log integration"
|
description: "Traefik reverse proxy metrics and access log integration"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/traefik-v1.0.0/traefik.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/traefik-v1.0.0/traefik.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- proxy
|
- proxy
|
||||||
@@ -62,12 +62,12 @@ plugins:
|
|||||||
- name: unifi
|
- name: unifi
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/unifi-v1.0.0/unifi.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/unifi-v1.0.0/unifi.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- network
|
- network
|
||||||
@@ -77,12 +77,12 @@ plugins:
|
|||||||
- name: ups
|
- name: ups
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
|
description: "UPS monitoring via NUT (Network UPS Tools) with Ansible shutdown automation"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/ups"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/ups"
|
||||||
download_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/releases/download/ups-v1.0.0/ups.zip"
|
download_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins/releases/download/ups-v1.0.0/ups.zip"
|
||||||
checksum_sha256: ""
|
checksum_sha256: ""
|
||||||
tags:
|
tags:
|
||||||
- ups
|
- ups
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
name: snmp
|
name: snmp
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
|
description: "SNMP polling for network devices — switches, routers, printers, UPSes, etc."
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/snmp"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/snmp"
|
||||||
tags:
|
tags:
|
||||||
- snmp
|
- snmp
|
||||||
- network
|
- network
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Synchronous SNMP GET helper, run via executor.
|
Synchronous SNMP GET helper, run via executor.
|
||||||
|
|
||||||
Requires pysnmp-lextudio (maintained pysnmp fork):
|
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.
|
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():
|
if not _pysnmp_available():
|
||||||
logger.warning("pysnmp not installed — SNMP polling disabled. "
|
logger.warning("pysnmp not installed — SNMP polling disabled. "
|
||||||
"Install with: pip install 'fabledscryer[snmp]'")
|
"Install with: pip install 'steward[snmp]'")
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
from pysnmp.hlapi import (
|
from pysnmp.hlapi import (
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ from datetime import datetime, timedelta, timezone
|
|||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import func, select
|
from sqlalchemy import func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.models.metrics import PluginMetric
|
from steward.models.metrics import PluginMetric
|
||||||
|
|
||||||
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
|
snmp_bp = Blueprint("snmp", __name__, template_folder="templates")
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING
|
|||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -27,16 +27,14 @@ def make_poll_task(app: "Quart") -> ScheduledTask:
|
|||||||
|
|
||||||
|
|
||||||
async def _do_poll(app: "Quart") -> None:
|
async def _do_poll(app: "Quart") -> None:
|
||||||
from datetime import datetime, timezone
|
|
||||||
from .poller import poll_device_sync
|
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", [])
|
devices: list[dict] = app.config["PLUGINS"]["snmp"].get("devices", [])
|
||||||
if not devices:
|
if not devices:
|
||||||
return
|
return
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
now = datetime.now(timezone.utc)
|
|
||||||
|
|
||||||
async with app.db_sessionmaker() as session:
|
async with app.db_sessionmaker() as session:
|
||||||
async with session.begin():
|
async with session.begin():
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/snmp/templates/snmp/device.html #}
|
{# plugins/snmp/templates/snmp/device.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}SNMP — {{ device_name }} — Fabled Scryer{% endblock %}
|
{% block title %}SNMP — {{ device_name }} — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;flex-wrap:wrap;">
|
<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;">← SNMP</a>
|
<a href="/plugins/snmp/" style="color:var(--text-muted);font-size:0.85rem;">← SNMP</a>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/snmp/templates/snmp/index.html #}
|
{# plugins/snmp/templates/snmp/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}SNMP — Fabled Scryer{% endblock %}
|
{% block title %}SNMP — Steward{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
|
<div style="display:flex;align-items:center;gap:1rem;margin-bottom:1.5rem;">
|
||||||
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
|
<h1 class="page-title" style="margin:0;">SNMP Devices</h1>
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ from sqlalchemy.engine import Connection
|
|||||||
from sqlalchemy.ext.asyncio import async_engine_from_config
|
from sqlalchemy.ext.asyncio import async_engine_from_config
|
||||||
from alembic import context
|
from alembic import context
|
||||||
|
|
||||||
# Make fabledscryer importable
|
# Make steward importable
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401 — core models
|
import steward.models # noqa: F401 — core models
|
||||||
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
|
from plugins.traefik.models import TraefikMetric # noqa: F401 — plugin model
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -31,14 +31,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import DateTime, Float, Integer, String, Text
|
from sqlalchemy import DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
from sqlalchemy.orm import Mapped, mapped_column
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
|
|
||||||
|
|
||||||
class TraefikMetric(Base):
|
class TraefikMetric(Base):
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
name: traefik
|
name: traefik
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "Traefik reverse proxy metrics and access log integration"
|
description: "Traefik reverse proxy metrics and access log integration"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/traefik"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/traefik"
|
||||||
tags:
|
tags:
|
||||||
- proxy
|
- proxy
|
||||||
- metrics
|
- metrics
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ from quart import Blueprint, current_app, render_template, request
|
|||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
||||||
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
|
from .models import TraefikAccessSummary, TraefikCert, TraefikGlobalStat, TraefikMetric
|
||||||
|
|
||||||
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
|
traefik_bp = Blueprint("traefik", __name__, template_folder="templates")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import time
|
|||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
@@ -41,7 +41,6 @@ async def _do_scrape(app: "Quart") -> None:
|
|||||||
global _prev_metrics, _prev_time
|
global _prev_metrics, _prev_time
|
||||||
|
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import select
|
|
||||||
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
|
from .models import TraefikCert, TraefikGlobalStat, TraefikMetric
|
||||||
from .scraper import (
|
from .scraper import (
|
||||||
compute_global_stats,
|
compute_global_stats,
|
||||||
@@ -49,7 +48,7 @@ async def _do_scrape(app: "Quart") -> None:
|
|||||||
extract_certs,
|
extract_certs,
|
||||||
fetch_metrics,
|
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"]
|
metrics_url: str = app.config["PLUGINS"]["traefik"]["metrics_url"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/traefik/templates/traefik/index.html #}
|
{# plugins/traefik/templates/traefik/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}Traefik — Fabled Scryer{% endblock %}
|
{% block title %}Traefik — Steward{% endblock %}
|
||||||
{% block content %}
|
{% 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:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.5rem;">
|
||||||
<div style="display:flex;align-items:baseline;gap:1rem;">
|
<div style="display:flex;align-items:baseline;gap:1rem;">
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ from alembic import context
|
|||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent))
|
||||||
|
|
||||||
from fabledscryer.models.base import Base
|
from steward.models.base import Base
|
||||||
import fabledscryer.models # noqa: F401
|
import steward.models # noqa: F401
|
||||||
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
|
from plugins.unifi.models import UnifiWanStat, UnifiClientSnapshot, UnifiDevice # noqa: F401
|
||||||
|
|
||||||
config = context.config
|
config = context.config
|
||||||
@@ -28,14 +28,14 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
def _get_url() -> str:
|
def _get_url() -> str:
|
||||||
import yaml
|
import yaml
|
||||||
cfg_path = os.environ.get("FABLEDSCRYER_CONFIG", "config.yaml")
|
cfg_path = os.environ.get("STEWARD_CONFIG", "config.yaml")
|
||||||
try:
|
try:
|
||||||
with open(cfg_path) as f:
|
with open(cfg_path) as f:
|
||||||
cfg = yaml.safe_load(f) or {}
|
cfg = yaml.safe_load(f) or {}
|
||||||
url = cfg.get("database", {}).get("url", "")
|
url = cfg.get("database", {}).get("url", "")
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
url = ""
|
url = ""
|
||||||
return os.environ.get("FABLEDSCRYER_DATABASE__URL", url)
|
return os.environ.get("STEWARD_DATABASE__URL", url)
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline() -> None:
|
def run_migrations_offline() -> None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import uuid
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
from sqlalchemy import Boolean, DateTime, Float, Integer, String, Text
|
||||||
from sqlalchemy.orm import Mapped, mapped_column
|
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) ──────────────────────────────────────────
|
# ── Time-series (one row per scrape) ──────────────────────────────────────────
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: unifi
|
name: unifi
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
description: "UniFi Network controller integration — WAN health, devices, clients, DPI"
|
||||||
author: "FabledScryer"
|
author: "Steward"
|
||||||
license: "MIT"
|
license: "MIT"
|
||||||
min_app_version: "0.1.0"
|
min_app_version: "0.1.0"
|
||||||
repository_url: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins"
|
repository_url: "https://git.fabledsword.com/bvandeusen/Steward-plugins"
|
||||||
homepage: "https://git.fabledsword.com/bvandeusen/FabledScryer-plugins/src/branch/main/unifi"
|
homepage: "https://git.fabledsword.com/bvandeusen/Steward-plugins/src/branch/main/unifi"
|
||||||
tags:
|
tags:
|
||||||
- network
|
- network
|
||||||
- unifi
|
- unifi
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
# plugins/unifi/routes.py
|
# plugins/unifi/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
import json
|
||||||
from datetime import datetime, timezone
|
|
||||||
from quart import Blueprint, current_app, render_template, request
|
from quart import Blueprint, current_app, render_template, request
|
||||||
from sqlalchemy import Integer, cast, func, select
|
from sqlalchemy import Integer, cast, func, select
|
||||||
|
|
||||||
from fabledscryer.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
from fabledscryer.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from fabledscryer.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds, subsample
|
from steward.core.time_range import parse_range, DEFAULT_RANGE, bucket_seconds
|
||||||
from .models import (
|
from .models import (
|
||||||
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
|
UnifiAlarm, UnifiClientSnapshot, UnifiDevice, UnifiDpiSnapshot,
|
||||||
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
|
UnifiEvent, UnifiFwRule, UnifiKnownClient, UnifiNetwork,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import logging
|
|||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from fabledscryer.core.scheduler import ScheduledTask
|
from steward.core.scheduler import ScheduledTask
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from quart import Quart
|
from quart import Quart
|
||||||
@@ -35,7 +35,7 @@ async def _do_poll(app: "Quart") -> None:
|
|||||||
|
|
||||||
from .client import UnifiClient
|
from .client import UnifiClient
|
||||||
from .models import UnifiClientSnapshot, UnifiDevice, UnifiWanStat
|
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"]
|
cfg = app.config["PLUGINS"]["unifi"]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{# plugins/unifi/templates/unifi/index.html #}
|
{# plugins/unifi/templates/unifi/index.html #}
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}UniFi — Fabled Scryer{% endblock %}
|
{% block title %}UniFi — Steward{% endblock %}
|
||||||
{% block content %}
|
{% 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:center;justify-content:space-between;flex-wrap:wrap;gap:0.75rem;margin-bottom:1.25rem;">
|
||||||
<div style="display:flex;align-items:baseline;gap:1rem;">
|
<div style="display:flex;align-items:baseline;gap:1rem;">
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import uuid
|
import uuid
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from quart import (
|
from quart import (
|
||||||
Blueprint, Response, current_app, redirect, render_template,
|
Blueprint, Response, current_app, render_template,
|
||||||
request, session, url_for,
|
request, session,
|
||||||
)
|
)
|
||||||
from sqlalchemy import select, update
|
from sqlalchemy import select
|
||||||
|
|
||||||
from steward.ansible import executor, sources as src_module
|
from steward.ansible import executor, sources as src_module
|
||||||
from steward.auth.middleware import require_role
|
from steward.auth.middleware import require_role
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ we trust the HTTPS connection to the discovery-documented token/userinfo endpoin
|
|||||||
"""
|
"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import base64
|
import base64
|
||||||
import hashlib
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# steward/core/plugin_manager.py
|
# steward/core/plugin_manager.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import hashlib
|
import hashlib
|
||||||
import importlib
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ Called by the scheduler (hourly check) or triggered manually from Settings.
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import smtplib
|
|
||||||
import ssl
|
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ target_metadata = Base.metadata
|
|||||||
|
|
||||||
|
|
||||||
def get_url() -> str:
|
def get_url() -> str:
|
||||||
import os, yaml
|
import os
|
||||||
|
import yaml
|
||||||
|
|
||||||
def _env(suffix: str) -> str | None:
|
def _env(suffix: str) -> str | None:
|
||||||
return os.environ.get(f"STEWARD_{suffix}")
|
return os.environ.get(f"STEWARD_{suffix}")
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# steward/settings/routes.py
|
# steward/settings/routes.py
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from quart import Blueprint, current_app, render_template, request, redirect, url_for, session
|
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.core.audit import log_audit
|
||||||
from steward.models.users import UserRole
|
from steward.models.users import UserRole
|
||||||
from steward.core.settings import (
|
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_smtp_cfg, to_webhook_cfg, to_ansible_cfg, to_plugins_cfg,
|
||||||
to_oidc_cfg, to_ldap_cfg,
|
to_oidc_cfg, to_ldap_cfg,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -144,12 +144,12 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Admin group DN</label>
|
<label>Admin group DN</label>
|
||||||
<input type="text" name="ldap.admin_group_dn" value="{{ settings['ldap.admin_group_dn'] }}"
|
<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>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Operator group DN</label>
|
<label>Operator group DN</label>
|
||||||
<input type="text" name="ldap.operator_group_dn" value="{{ settings['ldap.operator_group_dn'] }}"
|
<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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<div style="margin-bottom:2rem;max-width:720px;">
|
<div style="margin-bottom:2rem;max-width:720px;">
|
||||||
<div class="section-title" style="margin-bottom:0.75rem;">Plugin Repositories</div>
|
<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;">
|
<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.
|
and updated plugins. Add repos from other developers to expand the plugin catalog.
|
||||||
</p>
|
</p>
|
||||||
{% include "settings/_plugin_repos.html" %}
|
{% include "settings/_plugin_repos.html" %}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
from pathlib import Path
|
|
||||||
import textwrap
|
import textwrap
|
||||||
from steward.app import create_app
|
from steward.app import create_app
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import urllib.error
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
from plugins.host_agent import agent as a
|
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
|
assert payload["samples"][0]["cpu_pct"] == 5.0
|
||||||
|
|
||||||
|
|
||||||
import urllib.error
|
|
||||||
from unittest.mock import MagicMock, patch
|
|
||||||
|
|
||||||
|
|
||||||
def test_post_payload_success():
|
def test_post_payload_success():
|
||||||
from plugins.host_agent import agent as a
|
from plugins.host_agent import agent as a
|
||||||
captured = {}
|
captured = {}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ from plugins.host_agent.agent import RingBuffer
|
|||||||
|
|
||||||
def test_ring_buffer_preserves_order():
|
def test_ring_buffer_preserves_order():
|
||||||
rb = RingBuffer(maxlen=3)
|
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 list(rb.drain()) == [1, 2, 3]
|
||||||
assert len(rb) == 0
|
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():
|
def test_ring_buffer_drain_clears_and_is_atomic():
|
||||||
rb = RingBuffer(maxlen=5)
|
rb = RingBuffer(maxlen=5)
|
||||||
rb.push("a"); rb.push("b")
|
rb.push("a")
|
||||||
|
rb.push("b")
|
||||||
out = list(rb.drain())
|
out = list(rb.drain())
|
||||||
rb.push("c")
|
rb.push("c")
|
||||||
assert out == ["a", "b"]
|
assert out == ["a", "b"]
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import pytest
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
|
from plugins.host_agent.routes import _agent_version, AGENT_SOURCE_PATH
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import os
|
|
||||||
import textwrap
|
import textwrap
|
||||||
import pytest
|
import pytest
|
||||||
from steward.config import load_bootstrap
|
from steward.config import load_bootstrap
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import pytest
|
|
||||||
from steward.models.users import User, UserRole
|
from steward.models.users import User, UserRole
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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}"
|
||||||
Reference in New Issue
Block a user