Add formatting and type checks

This commit is contained in:
StasonJatham committed 2026-05-22 17:05:06 +02:00
1 parent c0d82eaf26
commit 24747866bc
38 files changed
+800 -265

No files matched your search

+19 -5
View File
@@ -138,8 +138,14 @@ def test_update_events_page_orders_raw_and_rollup_events_in_sql(tmp_path: Path)
store.log_update_rollup("rollup-mid.example.net", "203.0.113.3", None, "unchanged", "ok", "198.51.100.3")
with store.connect() as conn:
conn.execute("UPDATE update_events SET created_at = ? WHERE hostname = ?", ("2026-01-01T00:00:00+00:00", "raw-old.example.net"))
conn.execute("UPDATE update_events SET created_at = ? WHERE hostname = ?", ("2026-01-03T00:00:00+00:00", "raw-new.example.net"))
conn.execute(
"UPDATE update_events SET created_at = ? WHERE hostname = ?",
("2026-01-01T00:00:00+00:00", "raw-old.example.net"),
)
conn.execute(
"UPDATE update_events SET created_at = ? WHERE hostname = ?",
("2026-01-03T00:00:00+00:00", "raw-new.example.net"),
)
conn.execute(
"UPDATE update_event_rollups SET last_seen_at = ? WHERE hostname = ?",
("2026-01-02T00:00:00+00:00", "rollup-mid.example.net"),
@@ -156,8 +162,14 @@ def test_update_events_support_keyset_pagination(tmp_path: Path) -> None:
store.log_update_event("raw-old.example.net", "203.0.113.1", None, "updated", "ok", "198.51.100.1")
store.log_update_event("raw-new.example.net", "203.0.113.2", None, "updated", "ok", "198.51.100.2")
with store.connect() as conn:
conn.execute("UPDATE update_events SET created_at = ? WHERE hostname = ?", ("2026-01-01T00:00:00+00:00", "raw-old.example.net"))
conn.execute("UPDATE update_events SET created_at = ? WHERE hostname = ?", ("2026-01-02T00:00:00+00:00", "raw-new.example.net"))
conn.execute(
"UPDATE update_events SET created_at = ? WHERE hostname = ?",
("2026-01-01T00:00:00+00:00", "raw-old.example.net"),
)
conn.execute(
"UPDATE update_events SET created_at = ? WHERE hostname = ?",
("2026-01-02T00:00:00+00:00", "raw-new.example.net"),
)
app = make_app(DdnsSettings(database_path=database_path, admin_password="admin"))
client = TestClient(app)
@@ -247,7 +259,9 @@ def test_admin_can_rotate_links_and_password(tmp_path: Path) -> None:
)
assert update.status_code == 200
assert "Update URL changed" in update.text
assert client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
assert (
client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
)
management = client.post(
"/admin/hostnames/rotate",
+11 -20
View File
@@ -116,8 +116,7 @@ def test_first_run_creates_schema_and_repeated_startup_is_idempotent(tmp_path: P
def test_startup_migrates_legacy_cleanup_run_columns(tmp_path: Path) -> None:
database_path = tmp_path / "ddns.sqlite3"
with sqlite3.connect(database_path) as conn:
conn.execute(
"""
conn.execute("""
CREATE TABLE cleanup_runs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
created_at TEXT NOT NULL,
@@ -125,8 +124,7 @@ def test_startup_migrates_legacy_cleanup_run_columns(tmp_path: Path) -> None:
abandoned_setups_deleted INTEGER NOT NULL,
unused_accounts_deleted INTEGER NOT NULL
)
"""
)
""")
conn.execute(
"""
INSERT INTO cleanup_runs(
@@ -144,12 +142,10 @@ def test_startup_migrates_legacy_cleanup_run_columns(tmp_path: Path) -> None:
with store.connect() as conn:
columns = {row[1] for row in conn.execute("PRAGMA table_info(cleanup_runs)")}
row = conn.execute(
"""
row = conn.execute("""
SELECT unused_accounts_deleted
FROM cleanup_runs
"""
).fetchone()
""").fetchone()
assert columns == {"id", "created_at", "unused_accounts_deleted"}
assert tuple(row) == (1,)
@@ -225,16 +221,11 @@ def test_sqlite_startup_tuning_is_idempotent(tmp_path: Path) -> None:
temp_store = conn.execute("PRAGMA temp_store").fetchone()[0]
mmap_size = conn.execute("PRAGMA mmap_size").fetchone()[0]
user_version = conn.execute("PRAGMA user_version").fetchone()[0]
index_names = {
row[1]
for row in conn.execute(
"""
index_names = {row[1] for row in conn.execute("""
SELECT type, name
FROM sqlite_master
WHERE type = 'index'
"""
)
}
""")}
assert busy_timeout == 10_000
assert journal_mode == "wal"
@@ -255,8 +246,7 @@ def test_accounts_schema_migration_removes_legacy_router_credentials(tmp_path: P
database_path = tmp_path / "ddns.sqlite3"
with sqlite3.connect(database_path) as conn:
conn.execute("PRAGMA user_version = 2")
conn.execute(
"""
conn.execute("""
CREATE TABLE accounts (
hostname TEXT PRIMARY KEY,
username TEXT NOT NULL,
@@ -268,8 +258,7 @@ def test_accounts_schema_migration_removes_legacy_router_credentials(tmp_path: P
accepted_at TEXT,
disabled INTEGER NOT NULL DEFAULT 0
)
"""
)
""")
conn.execute(
"""
INSERT INTO accounts(
@@ -303,7 +292,9 @@ def test_accounts_schema_migration_removes_legacy_router_credentials(tmp_path: P
assert account["hostname"] == "home.ddns.example.net"
def test_rate_limit_flush_requeues_counts_after_database_failure(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
def test_rate_limit_flush_requeues_counts_after_database_failure(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
store = DdnsStore(tmp_path / "ddns.sqlite3")
assert store.allow_rate_limit("198.51.100.1:/api", 60) is True
+4 -1
View File
@@ -140,7 +140,10 @@ esac
assert "KarlDNS: registering hostname" in result.stdout
config = home_dir / ".config" / "karldns" / "updater.env"
config_text = config.read_text(encoding="utf-8")
assert "KARLDNS_UPDATE_URL='https://karldns.test/api/v1/router/update/karl_update_secret_12345678901234567890'" in config_text
assert (
"KARLDNS_UPDATE_URL='https://karldns.test/api/v1/router/update/karl_update_secret_12345678901234567890'"
in config_text
)
assert "KARLDNS_HOSTNAME='abc.karldns.test'" in config_text
+1 -1
View File
@@ -136,7 +136,7 @@ def test_dashboard_unlock_cookie_rejects_password_hash_signed_forgery(tmp_path:
def test_settings_reject_unknown_constructor_fields() -> None:
with pytest.raises(ValueError, match="Extra inputs are not permitted"):
DdnsSettings(admn_password="typo")
DdnsSettings(**{"admn_password": "typo"})
def test_trusted_host_middleware_rejects_unlisted_host(tmp_path: Path) -> None:
+40 -13
View File
@@ -58,7 +58,9 @@ def test_legacy_custom_account_form_is_rejected(tmp_path: Path) -> None:
)
client = TestClient(app)
response = client.post("/accounts", data={"mode": "custom", "hostname": "home.example.net", "claim_secret": "legacy"})
response = client.post(
"/accounts", data={"mode": "custom", "hostname": "home.example.net", "claim_secret": "legacy"}
)
assert response.status_code == 404
assert app.state.store.count_accounts() == 0
@@ -174,14 +176,18 @@ def test_generated_hostname_must_be_activated_before_updates_work(tmp_path: Path
account = app.state.store.get_account_by_management_slug(management_slug)
assert account["accepted_at"] is None
assert client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
assert (
client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
)
activated = client.post(f"/m/{management_slug}/activate", data={"csrf": _csrf(created.text)})
assert activated.status_code == 200
assert "Hostname registered" in activated.text
assert app.state.store.get_account_by_management_slug(management_slug)["accepted_at"]
assert client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 200
assert (
client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 200
)
def test_old_magic_route_is_gone(tmp_path: Path) -> None:
@@ -322,7 +328,10 @@ def test_management_dashboard_password_can_be_removed(tmp_path: Path) -> None:
unlock = client.post(
f"/m/{account['management_slug']}/unlock",
data={"csrf": _csrf(client.get(f"/m/{account['management_slug']}").text), "dashboard_password": "correct horse"},
data={
"csrf": _csrf(client.get(f"/m/{account['management_slug']}").text),
"dashboard_password": "correct horse",
},
)
assert unlock.status_code == 200
@@ -430,12 +439,18 @@ def test_management_dashboard_rotates_update_url(tmp_path: Path) -> None:
assert "data-secret-toggle" in dashboard.text
assert 'type="password"' in dashboard.text
rotated_update = client.post(f"/m/{account['management_slug']}/rotate", data={"csrf": _csrf(dashboard.text), "action": "update"})
rotated_update = client.post(
f"/m/{account['management_slug']}/rotate", data={"csrf": _csrf(dashboard.text), "action": "update"}
)
assert rotated_update.status_code == 200
assert "Update URL changed. Update your router now." in rotated_update.text
assert "data-secret-input" in rotated_update.text
assert client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
statuses = {event["status"] for event in app.state.store.list_update_events_for_hostname("home.ddns.example.net", 10)}
assert (
client.get(f"/api/v1/router/update/{account['update_slug']}", params={"myip": "203.0.113.9"}).status_code == 404
)
statuses = {
event["status"] for event in app.state.store.list_update_events_for_hostname("home.ddns.example.net", 10)
}
assert "dashboard_update_url_rotated" in statuses
assert "dashboard_router_credentials_rotated" not in statuses
@@ -449,13 +464,19 @@ def test_management_dashboard_actions_are_scoped_to_slug_owner(tmp_path: Path) -
client = TestClient(app)
dashboard = client.get(f"/m/{first['management_slug']}")
rotated = client.post(f"/m/{first['management_slug']}/rotate", data={"csrf": _csrf(dashboard.text), "action": "update"})
rotated = client.post(
f"/m/{first['management_slug']}/rotate", data={"csrf": _csrf(dashboard.text), "action": "update"}
)
assert rotated.status_code == 200
assert store.get_account_by_hostname("first.ddns.example.net")["update_slug"] != first["update_slug"]
assert store.get_account_by_hostname("second.ddns.example.net")["update_slug"] == second["update_slug"]
assert client.get(f"/api/v1/router/update/{first['update_slug']}", params={"myip": "203.0.113.1"}).status_code == 404
assert client.get(f"/api/v1/router/update/{second['update_slug']}", params={"myip": "203.0.113.2"}).status_code == 200
assert (
client.get(f"/api/v1/router/update/{first['update_slug']}", params={"myip": "203.0.113.1"}).status_code == 404
)
assert (
client.get(f"/api/v1/router/update/{second['update_slug']}", params={"myip": "203.0.113.2"}).status_code == 200
)
def test_locked_dashboard_rejects_mutating_actions_without_unlock_cookie(tmp_path: Path) -> None:
@@ -558,7 +579,10 @@ def test_public_examples_use_karldns_domain_and_no_shell_prompt(tmp_path: Path)
assert "https://karldns.de/api/v1/router/update/<secret>" in response.text
assert "http://127.0.0.1:8099/api/v1/router/update/<secret>" not in response.text
assert "$ curl" not in response.text
assert 'data-copy="curl -sS 'https://karldns.de/api/v1/router/update/<secret>?myip=203.0.113.10'"' in response.text
assert (
'data-copy="curl -sS 'https://karldns.de/api/v1/router/update/<secret>?myip=203.0.113.10'"'
in response.text
)
def test_application_pages_use_stricter_script_csp(tmp_path: Path) -> None:
@@ -579,7 +603,10 @@ def test_application_pages_use_stricter_script_csp(tmp_path: Path) -> None:
assert "<style>" not in response.text
assert "script-src 'self' 'unsafe-inline'" in response.headers["content-security-policy"]
assert "style-src 'self'" in response.headers["content-security-policy"]
assert "connect-src 'self' https://api4.ipify.org https://api6.ipify.org" in response.headers["content-security-policy"]
assert (
"connect-src 'self' https://api4.ipify.org https://api6.ipify.org"
in response.headers["content-security-policy"]
)
assert "style-src 'self' 'unsafe-inline'" not in response.headers["content-security-policy"]
bootstrap_css = client.get("/bootstrap-subset.css")
assert bootstrap_css.status_code == 200
@@ -622,7 +649,7 @@ def test_footer_links_and_privacy_page_are_available(tmp_path: Path) -> None:
assert 'property="og:image:width" content="1200"' in response.text
assert 'property="og:image:height" content="630"' in response.text
assert 'name="twitter:card" content="summary_large_image"' in response.text
assert 'application/ld+json' in response.text
assert "application/ld+json" in response.text
assert "NetworkingApplication" in response.text
assert "Made with" in response.text
assert "❤️" in response.text
+6 -2
View File
@@ -16,7 +16,9 @@ def test_router_update_get_accepts_fritzbox_placeholders(tmp_path: Path) -> None
database_path = tmp_path / "ddns.sqlite3"
store = DdnsStore(database_path)
account = store.create_account("home.ddns.example.net", "router")
app = make_app(DdnsSettings(database_path=database_path, admin_password="admin", hostname_suffix="ddns.example.net"))
app = make_app(
DdnsSettings(database_path=database_path, admin_password="admin", hostname_suffix="ddns.example.net")
)
client = TestClient(app)
response = client.get(
@@ -182,7 +184,9 @@ def test_slug_update_rejects_hostname_outside_provider_suffix(tmp_path: Path) ->
database_path = tmp_path / "ddns.sqlite3"
store = DdnsStore(database_path)
account = store.create_account("home.example.net", "router")
app = make_app(DdnsSettings(database_path=database_path, admin_password="admin", hostname_suffix="ddns.example.net"))
app = make_app(
DdnsSettings(database_path=database_path, admin_password="admin", hostname_suffix="ddns.example.net")
)
client = TestClient(app)
response = client.get(_update_path(account), params={"myip": "203.0.113.9"})